﻿using System;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.ComTypes;
using Vanara.InteropServices;
using static Vanara.PInvoke.Rpc;
using STATSTG = System.Runtime.InteropServices.ComTypes.STATSTG;

namespace Vanara.PInvoke
{
	public static partial class Ole32
	{
		/// <summary>
		/// Identifies one of the marshaling context attributes that you can query by using the GetMarshalingContextAttribute method.
		/// </summary>
		// https://docs.microsoft.com/en-us/windows/win32/api/objidl/ne-objidl-co_marshaling_context_attributes typedef enum
		// CO_MARSHALING_CONTEXT_ATTRIBUTES { CO_MARSHALING_SOURCE_IS_APP_CONTAINER, CO_MARSHALING_CONTEXT_ATTRIBUTE_RESERVED_1,
		// CO_MARSHALING_CONTEXT_ATTRIBUTE_RESERVED_2, CO_MARSHALING_CONTEXT_ATTRIBUTE_RESERVED_3,
		// CO_MARSHALING_CONTEXT_ATTRIBUTE_RESERVED_4, CO_MARSHALING_CONTEXT_ATTRIBUTE_RESERVED_5,
		// CO_MARSHALING_CONTEXT_ATTRIBUTE_RESERVED_6, CO_MARSHALING_CONTEXT_ATTRIBUTE_RESERVED_7,
		// CO_MARSHALING_CONTEXT_ATTRIBUTE_RESERVED_8, CO_MARSHALING_CONTEXT_ATTRIBUTE_RESERVED_9,
		// CO_MARSHALING_CONTEXT_ATTRIBUTE_RESERVED_10, CO_MARSHALING_CONTEXT_ATTRIBUTE_RESERVED_11,
		// CO_MARSHALING_CONTEXT_ATTRIBUTE_RESERVED_12, CO_MARSHALING_CONTEXT_ATTRIBUTE_RESERVED_13,
		// CO_MARSHALING_CONTEXT_ATTRIBUTE_RESERVED_14, CO_MARSHALING_CONTEXT_ATTRIBUTE_RESERVED_15,
		// CO_MARSHALING_CONTEXT_ATTRIBUTE_RESERVED_16, CO_MARSHALING_CONTEXT_ATTRIBUTE_RESERVED_17,
		// CO_MARSHALING_CONTEXT_ATTRIBUTE_RESERVED_18 } ;
		[PInvokeData("objidl.h", MSDNShortId = "NE:objidl.CO_MARSHALING_CONTEXT_ATTRIBUTES")]
		public enum CO_MARSHALING_CONTEXT_ATTRIBUTES
		{
			/// <summary>
			/// This attribute is a boolean value, with 0 representing TRUE and nonzero representing FALSE. You can safely cast the value of
			/// the result to BOOL, but it isn't safe for the caller to cast a BOOL* to ULONG_PTR* for the pAttributeValue parameter, or for
			/// the implementation to cast pAttributeValue to BOOL* when setting it.
			/// </summary>
			CO_MARSHALING_SOURCE_IS_APP_CONTAINER,

			/// <summary/>
			CO_MARSHALING_CONTEXT_ATTRIBUTE_RESERVED_1,

			/// <summary/>
			CO_MARSHALING_CONTEXT_ATTRIBUTE_RESERVED_2,

			/// <summary/>
			CO_MARSHALING_CONTEXT_ATTRIBUTE_RESERVED_3,

			/// <summary/>
			CO_MARSHALING_CONTEXT_ATTRIBUTE_RESERVED_4,

			/// <summary/>
			CO_MARSHALING_CONTEXT_ATTRIBUTE_RESERVED_5,

			/// <summary/>
			CO_MARSHALING_CONTEXT_ATTRIBUTE_RESERVED_6,

			/// <summary/>
			CO_MARSHALING_CONTEXT_ATTRIBUTE_RESERVED_7,

			/// <summary/>
			CO_MARSHALING_CONTEXT_ATTRIBUTE_RESERVED_8,

			/// <summary/>
			CO_MARSHALING_CONTEXT_ATTRIBUTE_RESERVED_9,

			/// <summary/>
			CO_MARSHALING_CONTEXT_ATTRIBUTE_RESERVED_10,

			/// <summary/>
			CO_MARSHALING_CONTEXT_ATTRIBUTE_RESERVED_11,

			/// <summary/>
			CO_MARSHALING_CONTEXT_ATTRIBUTE_RESERVED_12,

			/// <summary/>
			CO_MARSHALING_CONTEXT_ATTRIBUTE_RESERVED_13,

			/// <summary/>
			CO_MARSHALING_CONTEXT_ATTRIBUTE_RESERVED_14,
		}

		/// <summary>Specifies various capabilities in CoInitializeSecurity and IClientSecurity::SetBlanket (or its helper function CoSetProxyBlanket).</summary>
		/// <remarks>
		/// <para>
		/// When the EOAC_APPID flag is set, CoInitializeSecurity looks for the authentication level under the AppID. If the authentication
		/// level is not found, it looks for the default authentication level. If the default authentication level is not found, it
		/// generates a default authentication level of connect. If the authentication level is not RPC_C_AUTHN_LEVEL_NONE,
		/// <c>CoInitializeSecurity</c> looks for the access permission value under the AppID. If not found, it looks for the default access
		/// permission value. If not found, it generates a default access permission. All the other security settings are determined the
		/// same way as for a legacy application.
		/// </para>
		/// <para>
		/// If the AppID is NULL, <c>CoInitializeSecurity</c> looks up the application .exe name in the registry and uses the AppID stored
		/// there. If the AppID does not exist, the machine defaults are used.
		/// </para>
		/// <para>
		/// The IClientSecurity::SetBlanket method and CoSetProxyBlanket function return an error if any of the following flags are set in
		/// the capabilities parameter: EOAC_SECURE_REFS, EOAC_ACCESS_CONTROL, EOAC_APPID, EOAC_DYNAMIC, EOAC_REQUIRE_FULLSIC,
		/// EOAC_DISABLE_AAA, or EOAC_NO_CUSTOM_MARSHAL.
		/// </para>
		/// </remarks>
		// https://docs.microsoft.com/en-us/windows/win32/api/objidlbase/ne-objidlbase-eole_authentication_capabilities typedef enum
		// tagEOLE_AUTHENTICATION_CAPABILITIES { EOAC_NONE, EOAC_MUTUAL_AUTH, EOAC_STATIC_CLOAKING, EOAC_DYNAMIC_CLOAKING,
		// EOAC_ANY_AUTHORITY, EOAC_MAKE_FULLSIC, EOAC_DEFAULT, EOAC_SECURE_REFS, EOAC_ACCESS_CONTROL, EOAC_APPID, EOAC_DYNAMIC,
		// EOAC_REQUIRE_FULLSIC, EOAC_AUTO_IMPERSONATE, EOAC_DISABLE_AAA, EOAC_NO_CUSTOM_MARSHAL, EOAC_RESERVED1 } EOLE_AUTHENTICATION_CAPABILITIES;
		[PInvokeData("objidlbase.h", MSDNShortId = "NE:objidlbase.tagEOLE_AUTHENTICATION_CAPABILITIES")]
		[Flags]
		public enum EOLE_AUTHENTICATION_CAPABILITIES
		{
			/// <summary>Indicates that no capability flags are set.</summary>
			EOAC_NONE = 0x0,

			/// <summary>
			/// If this flag is specified, it will be ignored. Support for mutual authentication is automatically provided by some
			/// authentication services. See COM and Security Packages for more information.
			/// </summary>
			EOAC_MUTUAL_AUTH = 0x1,

			/// <summary>
			/// Sets static cloaking. When this flag is set, DCOM uses the thread token (if present) when determining the client's identity.
			/// However, the client's identity is determined on the first call on each proxy (if SetBlanket is not called) and each time
			/// CoSetProxyBlanket is called on the proxy. For more information about static cloaking, see Cloaking.CoInitializeSecurity and
			/// IClientSecurity::SetBlanket return errors if both cloaking flags are set or if either flag is set when Schannel is the
			/// authentication service.
			/// </summary>
			EOAC_STATIC_CLOAKING = 0x20,

			/// <summary>
			/// Sets dynamic cloaking. When this flag is set, DCOM uses the thread token (if present) when determining the client's
			/// identity. On each call to a proxy, the current thread token is examined to determine whether the client's identity has
			/// changed (incurring an additional performance cost) and the client is authenticated again only if necessary. Dynamic cloaking
			/// can be set by clients only. For more information about dynamic cloaking, see Cloaking.CoInitializeSecurity and
			/// IClientSecurity::SetBlanket return errors if both cloaking flags are set or if either flag is set when Schannel is the
			/// authentication service.
			/// </summary>
			EOAC_DYNAMIC_CLOAKING = 0x40,

			/// <summary>This flag is obsolete.</summary>
			EOAC_ANY_AUTHORITY = 0x80,

			/// <summary>
			/// Causes DCOM to send Schannel server principal names in fullsic format to clients as part of the default security
			/// negotiation. The name is extracted from the server certificate. For more information about the fullsic form, see Principal Names.
			/// </summary>
			EOAC_MAKE_FULLSIC = 0x100,

			/// <summary>
			/// Tells DCOM to use the valid capabilities from the call to CoInitializeSecurity. If CoInitializeSecurity was not called,
			/// EOAC_NONE will be used for the capabilities flag. This flag can be set only by clients in a call to
			/// IClientSecurity::SetBlanket or CoSetProxyBlanket.
			/// </summary>
			EOAC_DEFAULT = 0x800,

			/// <summary>
			/// Authenticates distributed reference count calls to prevent malicious users from releasing objects that are still being used.
			/// If this flag is set, which can be done only in a call to CoInitializeSecurity by the client, the authentication level (in
			/// dwAuthnLevel) cannot be set to none.The server always authenticates Release calls. Setting this flag prevents an
			/// authenticated client from releasing the objects of another authenticated client. It is recommended that clients always set
			/// this flag, although performance is affected because of the overhead associated with the extra security.
			/// </summary>
			EOAC_SECURE_REFS = 0x2,

			/// <summary>
			/// Indicates that the pSecDesc parameter to CoInitializeSecurity is a pointer to an IAccessControl interface on an access
			/// control object. When DCOM makes security checks, it calls IAccessControl::IsAccessAllowed. This flag is set only by the
			/// server.CoInitializeSecurity returns an error if both the EOAC_APPID and EOAC_ACCESS_CONTROL flags are set.
			/// </summary>
			EOAC_ACCESS_CONTROL = 0x4,

			/// <summary>
			/// Indicates that the pSecDesc parameter to CoInitializeSecurity is a pointer to a GUID that is an AppID. The
			/// CoInitializeSecurity function looks up the AppID in the registry and reads the security settings from there. If this flag is
			/// set, all other parameters to CoInitializeSecurity are ignored and must be zero. Only the server can set this flag. For more
			/// information about this capability flag, see the Remarks section below.CoInitializeSecurity returns an error if both the
			/// EOAC_APPID and EOAC_ACCESS_CONTROL flags are set.
			/// </summary>
			EOAC_APPID = 0x8,

			/// <summary>Reserved.</summary>
			EOAC_DYNAMIC = 0x10,

			/// <summary>
			/// Causes DCOM to fail CoSetProxyBlanket calls where an Schannel principal name is specified in any format other than fullsic.
			/// This flag is currently for clients only. For more information about the fullsic form, see Principal Names.
			/// </summary>
			EOAC_REQUIRE_FULLSIC = 0x200,

			/// <summary>Reserved.</summary>
			EOAC_AUTO_IMPERSONATE = 0x400,

			/// <summary>
			/// Causes any activation where a server process would be launched under the caller's identity (activate-as-activator) to fail
			/// with E_ACCESSDENIED. This value, which can be specified only in a call to CoInitializeSecurity by the client, allows an
			/// application that runs under a privileged account (such as LocalSystem) to help prevent its identity from being used to
			/// launch untrusted components.An activation call that uses CLSCTX_ENABLE_AAA of the CLSCTX enumeration will allow
			/// activate-as-activator activations for that call.
			/// </summary>
			EOAC_DISABLE_AAA = 0x1000,

			/// <summary>
			/// Specifying this flag helps protect server security when using DCOM or COM+. It reduces the chances of executing arbitrary
			/// DLLs because it allows the marshaling of only CLSIDs that are implemented in Ole32.dll, ComAdmin.dll, ComSvcs.dll, or
			/// Es.dll, or that implement the CATID_MARSHALER category ID. Any service that is critical to system operation should set this flag.
			/// </summary>
			EOAC_NO_CUSTOM_MARSHAL = 0x2000,

			/// <summary/>
			EOAC_RESERVED1 = 0x4000,
		}

		/// <summary>Specifies the type of external connection existing on an embedded object.</summary>
		// https://docs.microsoft.com/en-us/windows/win32/api/objidlbase/ne-objidlbase-extconn typedef enum tagEXTCONN { EXTCONN_STRONG,
		// EXTCONN_WEAK, EXTCONN_CALLABLE } EXTCONN;
		[PInvokeData("objidlbase.h", MSDNShortId = "NE:objidlbase.tagEXTCONN")]
		[Flags]
		public enum EXTCONN
		{
			/// <summary>
			/// The external connection is a link. If this value is specified, the external connection must keep the object alive until all
			/// strong external connections are cleared through IExternalConnection::ReleaseConnection.
			/// </summary>
			EXTCONN_STRONG = 0x0001,

			/// <summary>This value is not used.</summary>
			EXTCONN_WEAK = 0x0002,

			/// <summary>This value is not used.</summary>
			EXTCONN_CALLABLE = 0x0004,
		}

		/// <summary>Identifies process-global options that you can set or query by using the IGlobalOptions interface.</summary>
		/// <remarks>
		/// The unmarshaling policy option <c>COMGLB_UNMARSHALING_POLICY</c> takes values from the GLOBALOPT_UNMARSHALING_POLICY_VALUES enumeration.
		/// </remarks>
		// https://docs.microsoft.com/en-us/windows/win32/api/objidlbase/ne-objidlbase-globalopt_properties typedef enum
		// tagGLOBALOPT_PROPERTIES { COMGLB_EXCEPTION_HANDLING, COMGLB_APPID, COMGLB_RPC_THREADPOOL_SETTING, COMGLB_RO_SETTINGS,
		// COMGLB_UNMARSHALING_POLICY, COMGLB_PROPERTIES_RESERVED1, COMGLB_PROPERTIES_RESERVED2, COMGLB_PROPERTIES_RESERVED3 } GLOBALOPT_PROPERTIES;
		[PInvokeData("objidlbase.h", MSDNShortId = "NE:objidlbase.tagGLOBALOPT_PROPERTIES")]
		public enum GLOBALOPT_PROPERTIES
		{
			/// <summary>Defines COM exception-handling behavior.</summary>
			COMGLB_EXCEPTION_HANDLING = 1,

			/// <summary>Sets the AppID for the process.</summary>
			COMGLB_APPID,

			/// <summary>Sets the thread-pool behavior of the RPC runtime in the process.</summary>
			COMGLB_RPC_THREADPOOL_SETTING,

			/// <summary>Used for miscellaneous settings.</summary>
			COMGLB_RO_SETTINGS,

			/// <summary>Defines the policy that's applied in the CoUnmarshalInterface function.</summary>
			COMGLB_UNMARSHALING_POLICY,

			/// <summary/>
			COMGLB_PROPERTIES_RESERVED1,

			/// <summary/>
			COMGLB_PROPERTIES_RESERVED2,

			/// <summary/>
			COMGLB_PROPERTIES_RESERVED3,
		}

		/// <summary>
		/// The <c>LOCKTYPE</c> enumeration values indicate the type of locking requested for the specified range of bytes. The values are
		/// used in the ILockBytes::LockRegion and IStream::LockRegion methods.
		/// </summary>
		// https://docs.microsoft.com/en-us/windows/desktop/api/objidl/ne-objidl-taglocktype typedef enum tagLOCKTYPE { LOCK_WRITE,
		// LOCK_EXCLUSIVE, LOCK_ONLYONCE } LOCKTYPE;
		[PInvokeData("objidl.h", MSDNShortId = "5d84fb08-aa4f-4918-a0de-550b02cb5287")]
		[Flags]
		public enum LOCKTYPE
		{
			/// <summary>
			/// If this lock is granted, the specified range of bytes can be opened and read any number of times, but writing to the locked
			/// range is prohibited except for the owner that was granted this lock.
			/// </summary>
			LOCK_WRITE = 1,

			/// <summary>
			/// If this lock is granted, writing to the specified range of bytes is prohibited except by the owner that was granted this lock.
			/// </summary>
			LOCK_EXCLUSIVE = 2,

			/// <summary>
			/// If this lock is granted, no other LOCK_ONLYONCE lock can be obtained on the range. Usually this lock type is an alias for
			/// some other lock type. Thus, specific implementations can have additional behavior associated with this lock type.
			/// </summary>
			LOCK_ONLYONCE = 4,
		}

		/// <summary>An identifier of the property to be queried or set.</summary>
		[PInvokeData("objidl.h", MSDNShortId = "NN:objidl.IRpcOptions")]
		[Flags]
		public enum RPCOPT_PROPERTIES
		{
			/// <summary>Controls how long your machine will attempt to establish RPC communications with another before failing.</summary>
			[CorrespondingType(typeof(Rpc.RCP_C_BINDING_TIMEOUT), CorrespondingAction.GetSet)]
			COMBND_RPCTIMEOUT = 0x01,

			/// <summary>Describes the degree of remoteness of the RPC connection.</summary>
			[CorrespondingType(typeof(RPCOPT_SERVER_LOCALITY_VALUES), CorrespondingAction.Get)]
			COMBND_SERVER_LOCALITY = 0x02,

			/// <summary>Reserved.</summary>
			COMBND_RESERVED1 = 0x04,

			/// <summary>Reserved.</summary>
			COMBND_RESERVED2 = 0x05,

			/// <summary>Reserved.</summary>
			COMBND_RESERVED3 = 0x08,

			/// <summary>Reserved.</summary>
			COMBND_RESERVED4 = 0x10,
		}

		/// <summary>Describes the degree of remoteness of the RPC connection.</summary>
		[PInvokeData("objidl.h", MSDNShortId = "NN:objidl.IRpcOptions")]
		public enum RPCOPT_SERVER_LOCALITY_VALUES
		{
			/// <summary>The counterpart is in the same process as the client.</summary>
			SERVER_LOCALITY_PROCESS_LOCAL = 0,

			/// <summary>The counterpart is on the same computer as the client but in a different process.</summary>
			SERVER_LOCALITY_MACHINE_LOCAL = 1,

			/// <summary>The counterpart is on a remote computer.</summary>
			SERVER_LOCALITY_REMOTE = 2
		}

		/// <summary>
		/// The <c>STREAM_SEEK</c> enumeration values specify the origin from which to calculate the new seek-pointer location. They are
		/// used for the dworigin parameter in the IStream::Seek method. The new seek position is calculated using this value and the
		/// dlibMove parameter.
		/// </summary>
		// https://docs.microsoft.com/en-us/windows/win32/api/objidl/ne-objidl-stream_seek typedef enum tagSTREAM_SEEK { STREAM_SEEK_SET,
		// STREAM_SEEK_CUR, STREAM_SEEK_END } STREAM_SEEK;
		[PInvokeData("objidl.h", MSDNShortId = "NE:objidl.tagSTREAM_SEEK")]
		public enum STREAM_SEEK
		{
			/// <summary>
			/// The new seek pointer is an offset relative to the beginning of the stream. In this case, the dlibMove parameter is the new
			/// seek position relative to the beginning of the stream.
			/// </summary>
			STREAM_SEEK_SET,

			/// <summary>
			/// The new seek pointer is an offset relative to the current seek pointer location. In this case, the dlibMove parameter is the
			/// signed displacement from the current seek position.
			/// </summary>
			STREAM_SEEK_CUR,

			/// <summary>
			/// The new seek pointer is an offset relative to the end of the stream. In this case, the dlibMove parameter is the new seek
			/// position relative to the end of the stream.
			/// </summary>
			STREAM_SEEK_END,
		}

		/// <summary>Indicates whether a particular thread supports a message loop.</summary>
		// https://docs.microsoft.com/en-us/windows/win32/api/objidl/ne-objidl-thdtype typedef enum _THDTYPE { THDTYPE_BLOCKMESSAGES,
		// THDTYPE_PROCESSMESSAGES } THDTYPE;
		[PInvokeData("objidl.h", MSDNShortId = "NE:objidl._THDTYPE")]
		public enum THDTYPE
		{
			/// <summary>The thread does not support a message loop. This behavior is associated with multithreaded apartments.</summary>
			THDTYPE_BLOCKMESSAGES,

			/// <summary>The thread supports a message loop. This behavior is associated with single-threaded apartments.</summary>
			THDTYPE_PROCESSMESSAGES,
		}

		/// <summary>Undocumented.</summary>
		[PInvokeData("objidl.h")]
		[ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("00000017-0000-0000-C000-000000000046")]
		public interface IActivationFilter
		{
			/// <summary>Handles the activation.</summary>
			/// <param name="dwActivationType">Type of the activation.</param>
			/// <param name="rclsid">The CLSID.</param>
			/// <param name="pReplacementClsId">The replacement CLSID.</param>
			/// <returns>An appropriate error response.</returns>
			[PreserveSig]
			HRESULT HandleActivation(ACTIVATIONTYPE dwActivationType, in Guid rclsid, out Guid pReplacementClsId);
		}

		/// <summary>Creates a call object for processing calls to the methods of an asynchronous interface.</summary>
		// https://docs.microsoft.com/en-us/windows/win32/api/objidlbase/nn-objidlbase-icallfactory
		[PInvokeData("objidlbase.h", MSDNShortId = "NN:objidlbase.ICallFactory")]
		[ComImport, Guid("1c733a30-2a1c-11ce-ade5-00aa0044773d"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
		public interface ICallFactory
		{
			/// <summary>Creates an instance of the call object that corresponds to a specified asynchronous interface.</summary>
			/// <param name="riid">A reference to the identifier for the asynchronous interface.</param>
			/// <param name="pCtrlUnk">
			/// A pointer to the controlling IUnknown of the call object. If this parameter is not <c>NULL</c>, the call object is
			/// aggregated in the specified object. If this parameter is <c>NULL</c>, the call object is not aggregated.
			/// </param>
			/// <param name="riid2">The identifier of an interface on the call object. Typical values are IID_IUnknown and IID_ISynchronize.</param>
			/// <param name="ppv">The address of a pointer to the interface specified by riid2. This parameter cannot be <c>NULL</c>.</param>
			/// <returns>
			/// <para>
			/// This method can return the standard return values E_INVALIDARG, E_OUTOFMEMORY, and E_UNEXPECTED, as well as the following values.
			/// </para>
			/// <list type="table">
			/// <listheader>
			/// <term>Return code</term>
			/// <term>Description</term>
			/// </listheader>
			/// <item>
			/// <term>S_OK</term>
			/// <term>The call object was created successfully.</term>
			/// </item>
			/// <item>
			/// <term>E_NOINTERFACE</term>
			/// <term>The riid parameter does not reference the identifier for the asynchronous interface, such as IID_AsyncIEventSourceCallback.</term>
			/// </item>
			/// </list>
			/// </returns>
			// https://docs.microsoft.com/en-us/windows/win32/api/objidl/nf-objidl-icallfactory-createcall HRESULT CreateCall( REFIID riid,
			// IUnknown *pCtrlUnk, REFIID riid2, IUnknown **ppv );
			[PreserveSig]
			HRESULT CreateCall(in Guid riid, [In, Optional, MarshalAs(UnmanagedType.IUnknown, IidParameterIndex = 0)] object pCtrlUnk,
				in Guid riid2, [MarshalAs(UnmanagedType.IUnknown, IidParameterIndex = 2)] out object ppv);
		}

		/// <summary>
		/// Manages cancellation requests on an outbound method call and monitors the current state of that method call on the server thread.
		/// </summary>
		// https://docs.microsoft.com/en-us/windows/win32/api/objidl/nn-objidl-icancelmethodcalls
		[PInvokeData("objidl.h", MSDNShortId = "NN:objidl.ICancelMethodCalls")]
		[ComImport, Guid("00000029-0000-0000-C000-000000000046"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
		public interface ICancelMethodCalls
		{
			/// <summary>Requests that a method call be canceled.</summary>
			/// <param name="ulSeconds">
			/// The number of seconds to wait for the server to complete the outbound call after the client requests cancellation.
			/// </param>
			/// <returns>
			/// <para>This method can return one of these values.</para>
			/// <list type="table">
			/// <listheader>
			/// <term>Return code</term>
			/// <term>Description</term>
			/// </listheader>
			/// <item>
			/// <term>S_OK</term>
			/// <term>The cancellation request was made.</term>
			/// </item>
			/// <item>
			/// <term>RPC_S_CALL_CANCELED</term>
			/// <term>The call was already canceled.</term>
			/// </item>
			/// <item>
			/// <term>CO_E_CANCEL_DISABLED</term>
			/// <term>Call cancellation is not enabled on the thread that is processing the call.</term>
			/// </item>
			/// <item>
			/// <term>RPC_E_CALL_COMPLETE</term>
			/// <term>The call was completed during the timeout interval.</term>
			/// </item>
			/// </list>
			/// </returns>
			/// <remarks>
			/// <para>
			/// The <c>Cancel</c> method only issues a cancel request. A return value of S_OK does not mean that the call was canceled, only
			/// that an attempt was made to cancel the call. The behavior of the cancel object on receiving a cancel request is entirely at
			/// the discretion of the implementer.
			/// </para>
			/// <para>If a method that returns an <c>HRESULT</c> is canceled, the return value will be RPC_S_CALL_CANCELED.</para>
			/// </remarks>
			// https://docs.microsoft.com/en-us/windows/win32/api/objidl/nf-objidl-icancelmethodcalls-cancel HRESULT Cancel( ULONG ulSeconds );
			[PreserveSig]
			HRESULT Cancel([In] uint ulSeconds);

			/// <summary>Determines whether a call has been canceled.</summary>
			/// <returns>If the call was canceled, the return value is RPC_E_CALL_CANCELED. Otherwise, it is RPC_S_CALLPENDING.</returns>
			/// <remarks>
			/// <para>
			/// The server object calls <c>TestCancel</c> to determine if the call has been canceled. If the call has been canceled, the
			/// server should clean up the necessary resources and return control to the client.
			/// </para>
			/// <para>This method can be called from both the client and the server.</para>
			/// </remarks>
			// https://docs.microsoft.com/en-us/windows/win32/api/objidl/nf-objidl-icancelmethodcalls-testcancel HRESULT TestCancel();
			[PreserveSig]
			HRESULT TestCancel();
		}

		/// <summary>Provides a mechanism to intercept and modify calls when the COM engine processes the calls.</summary>
		[PInvokeData("objidlbase.h")]
		[ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("1008c4a0-7613-11cf-9af1-0020af6e72f4")]
		public interface IChannelHook
		{
			/// <summary/>
			[PreserveSig]
			void ClientGetSize(in Guid uExtent, in Guid riid, out uint pDataSize);

			/// <summary/>
			[PreserveSig]
			void ClientFillBuffer(in Guid uExtent, in Guid riid, ref uint pDataSize, IntPtr pDataBuffer);

			/// <summary/>
			[PreserveSig]
			void ClientNotify(in Guid uExtent, in Guid riid, uint cbDataSize, IntPtr pDataBuffer, uint lDataRep, HRESULT hrFault);

			/// <summary/>
			[PreserveSig]
			void ServerNotify(in Guid uExtent, in Guid riid, uint cbDataSize, IntPtr pDataBuffer, uint lDataRep);

			/// <summary/>
			[PreserveSig]
			void ServerGetSize(in Guid uExtent, in Guid riid, HRESULT hrFault, out uint pDataSize);

			/// <summary/>
			[PreserveSig]
			void ServerFillBuffer(in Guid uExtent, in Guid riid, ref uint pDataSize, IntPtr pDataBuffer, HRESULT hrFault);
		}

		/// <summary>Gives the client control over the security settings for each individual interface proxy of an object.</summary>
		/// <remarks>
		/// <para>
		/// Every object has one proxy manager, and every proxy manager exposes the <c>IClientSecurity</c> interface automatically.
		/// Therefore, the client can query the proxy manager of an object for <c>IClientSecurity</c>, using any interface pointer on the
		/// object. If the QueryInterface call succeeds, the <c>IClientSecurity</c> pointer can be used to call an <c>IClientSecurity</c>
		/// method, passing a pointer to the interface proxy that the client is interested in. If a call to <c>QueryInterface</c> for
		/// <c>IClientSecurity</c> fails, either the object is implemented in-process or it is remoted by a custom marshaler that does not
		/// support security. (A custom marshaler can support security by offering the <c>IClientSecurity</c> interface to the client.)
		/// </para>
		/// <para>
		/// The interface proxies passed as parameters to <c>IClientSecurity</c> methods must be from the same object as the
		/// <c>IClientSecurity</c> interface. That is, each object has a distinct <c>IClientSecurity</c> interface; calling
		/// <c>IClientSecurity</c> on one object and passing a proxy to another object will not work. Also, you cannot pass an interface to
		/// an <c>IClientSecurity</c> method if the interface does not use a proxy. This means that interfaces implemented locally by the
		/// proxy manager cannot be passed to <c>IClientSecurity</c> methods, except for IUnknown, which is the exception to this rule.
		/// </para>
		/// </remarks>
		// https://docs.microsoft.com/en-us/windows/win32/api/objidl/nn-objidl-iclientsecurity
		[PInvokeData("objidl.h", MSDNShortId = "NN:objidl.IClientSecurity")]
		[ComImport, Guid("0000013D-0000-0000-C000-000000000046"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
		public interface IClientSecurity
		{
			/// <summary>Retrieves authentication information the client uses to make calls on the specified proxy.</summary>
			/// <param name="pProxy">
			/// A pointer to the proxy. This parameter cannot be <c>NULL</c>. For more information, see the Remarks section.
			/// </param>
			/// <param name="pAuthnSvc">
			/// The current authentication service. This will be a single value taken from the list of authentication service constants.
			/// This parameter cannot be <c>NULL</c>.
			/// </param>
			/// <param name="pAuthzSvc">
			/// The current authorization service. This will be a single value taken from the list of authorization constants. This
			/// parameter cannot be <c>NULL</c>.
			/// </param>
			/// <param name="pServerPrincName">
			/// The current principal name. The string will be allocated by the callee using the CoTaskMemAlloc function and must be freed
			/// by the caller using the CoTaskMemFree function. Note that the actual principal name is returned. The EOAC_MAKE_FULLSIC flag
			/// is not accepted to convert the prinicpal name. If the caller specifies <c>NULL</c>, the current principal name is not retrieved.
			/// </param>
			/// <param name="pAuthnLevel">
			/// The current authentication level. This will be a single value taken from the list of authentication level constants. If this
			/// parameter is <c>NULL</c>, the current authentication level is not retrieved.
			/// </param>
			/// <param name="pImpLevel">
			/// The current impersonation level. This will be a single value taken from the list of impersonation level constants. If this
			/// parameter is <c>NULL</c>, the current impersonation level is not retrieved.
			/// </param>
			/// <param name="pAuthInfo">
			/// <para>
			/// A pointer to a handle indicating the identity of the client that was passed to the last IClientSecurity::SetBlanket call (or
			/// the default value). Default values are only valid until the proxy is released. If the caller specifies <c>NULL</c>, the
			/// client identity is not retrieved.
			/// </para>
			/// <para>
			/// The format of the structure that the returned handle refers to depends on the authentication service. For NTLMSSP and
			/// Kerberos, if the client specified a structure in the pAuthInfo parameter to CoInitializeSecurity, that value is returned.
			/// For Schannel, if a certificate for the client could be retrieved from the certificate manager, that value is returned here.
			/// Otherwise, <c>NULL</c> is returned. Because this points to the value itself and is not a copy, it should not be manipulated
			/// or freed.
			/// </para>
			/// </param>
			/// <param name="pCapabilites">
			/// The capabilities of the proxy. These flags are defined in the EOLE_AUTHENTICATION_CAPABILITIES enumeration. If this
			/// parameter is <c>NULL</c>, the current capability flags are not retrieved.
			/// </param>
			/// <returns>
			/// <para>This method can return the following values.</para>
			/// <list type="table">
			/// <listheader>
			/// <term>Return code</term>
			/// <term>Description</term>
			/// </listheader>
			/// <item>
			/// <term>S_OK</term>
			/// <term>The method completed successfully.</term>
			/// </item>
			/// <item>
			/// <term>E_INVALIDARG</term>
			/// <term>One or more arguments are not valid.</term>
			/// </item>
			/// <item>
			/// <term>E_OUTOFMEMORY</term>
			/// <term>There is insufficient memory to create the pServerPrincName buffer.</term>
			/// </item>
			/// </list>
			/// </returns>
			/// <remarks>
			/// <para>
			/// <c>QueryBlanket</c> is called by the client to retrieve the authentication information COM will use on calls made from the
			/// specified interface proxy. With a pointer to an interface on the proxy, the client would first call QueryInterface for a
			/// pointer to IClientSecurity; then, with this pointer, the client would call <c>QueryBlanket</c>, followed by releasing the
			/// pointer. This sequence of calls is encapsulated in the helper function CoQueryProxyBlanket.
			/// </para>
			/// <para>
			/// In pProxy, you pass an interface pointer. However, you cannot pass a pointer to an interface that does not use a proxy. Thus
			/// you cannot pass a pointer to an interface that has the local keyword in its interface definition since no proxy is created
			/// for such an interface. IUnknown is the exception to this rule.
			/// </para>
			/// </remarks>
			// https://docs.microsoft.com/en-us/windows/win32/api/objidl/nf-objidl-iclientsecurity-queryblanket HRESULT QueryBlanket(
			// IUnknown *pProxy, DWORD *pAuthnSvc, DWORD *pAuthzSvc, OLECHAR **pServerPrincName, DWORD *pAuthnLevel, DWORD *pImpLevel, void
			// **pAuthInfo, DWORD *pCapabilites );
			[PreserveSig]
			HRESULT QueryBlanket([In, MarshalAs(UnmanagedType.IUnknown)] object pProxy, out RPC_C_AUTHN pAuthnSvc, out RPC_C_AUTHZ pAuthzSvc,
				[MarshalAs(UnmanagedType.LPWStr)] out string pServerPrincName, out RPC_C_AUTHN_LEVEL pAuthnLevel, out RPC_C_IMP_LEVEL pImpLevel,
				out IntPtr pAuthInfo, out EOLE_AUTHENTICATION_CAPABILITIES pCapabilites);

			/// <summary>
			/// <para>Sets the authentication information (the security blanket) that will be used to make calls on the specified proxy.</para>
			/// <para>
			/// This setting overrides the process default settings for the specified proxy. Calling this method changes the security values
			/// for all other users of the specified proxy.
			/// </para>
			/// </summary>
			/// <param name="pProxy">A pointer to the proxy.</param>
			/// <param name="dwAuthnSvc">
			/// The authentication service. This will be a single value taken from the list of authentication service constants. If no
			/// authentication is required, use RPC_C_AUTHN_NONE. If RPC_C_AUTHN_DEFAULT is specified, COM will pick an authentication
			/// service following its normal security blanket negotiation algorithm.
			/// </param>
			/// <param name="dwAuthzSvc">
			/// The authorization service. This will be a single value taken from the list of authorization constants. If
			/// RPC_C_AUTHZ_DEFAULT is specified, COM will pick an authorization service following its normal security blanket negotiation
			/// algorithm. If NTLMSSP, Kerberos, or Schannel is used as the authentication service, RPC_C_AUTHZ_NONE should be used as the
			/// authorization service.
			/// </param>
			/// <param name="pServerPrincName">
			/// <para>
			/// The server principal name. If COLE_DEFAULT_PRINCIPAL is specified, DCOM will pick a principal name using its security
			/// blanket negotiation algorithm. If Kerberos is used as the authentication service, this parameter must be the correct
			/// principal name of the server or the call will fail.
			/// </para>
			/// <para>
			/// If Schannel is used as the authentication service, this value must be one of the msstd or fullsic forms described in
			/// Principal Names, or <c>NULL</c> if you do not want mutual authentication.
			/// </para>
			/// <para>
			/// Generally, specifying <c>NULL</c> will not reset server principal name on the proxy, rather, the previous setting will be
			/// retained. You must exercise care when using <c>NULL</c> as pServerPrincName when selecting a different authentication
			/// service for the proxy, because there is no guarantee that the previously set principal name would be valid for the newly
			/// selected authentication service.
			/// </para>
			/// </param>
			/// <param name="dwAuthnLevel">
			/// The authentication level. This will be a single value taken from the list of authentication level constants. If
			/// RPC_C_AUTHN_LEVEL_DEFAULT is specified, COM will pick an authentication level following its normal security blanket
			/// negotiation algorithm. If this value is set to RPC_C_AUTHN_LEVEL_NONE, the authentication service must be RPC_C_AUTHN_NONE.
			/// Each authentication service may choose to use a higher security authentication level than the one specified.
			/// </param>
			/// <param name="dwImpLevel">
			/// The impersonation level. This will be a single value taken from the list of impersonation level constants. If
			/// RPC_C_IMP_LEVEL_DEFAULT is specified, COM will pick an impersonation level following its normal security blanket negotiation
			/// algorithm. If you are using NTLMSSP remotely, this value must be RPC_C_IMP_LEVEL_IMPERSONATE or RPC_C_IMP_LEVEL_IDENTIFY.
			/// When using NTLMSSP on the same computer, RPC_C_IMP_LEVEL_DELEGATE is also supported. For Kerberos, this value can be
			/// RPC_C_IMP_LEVEL_IDENTIFY, RPC_C_IMP_LEVEL_IMPERSONATE, or RPC_C_IMP_LEVEL_DELEGATE. For Schannel, this value must be RPC_C_IMP_LEVEL_IMPERSONATE.
			/// </param>
			/// <param name="pAuthInfo">
			/// <para>
			/// An RPC_AUTH_IDENTITY_HANDLE value that indicates the identity of the client. This parameter is not used for calls on the
			/// same computer. If pAuthInfo is <c>NULL</c>, COM uses the current proxy identity, which is either the process token, the
			/// impersonation token, or the authentication identity from the CoInitializeSecurity function. If the handle is not
			/// <c>NULL</c>, that identity is used. The format of the structure referred to by the handle depends on the provider of the
			/// authentication service.
			/// </para>
			/// <para>
			/// For NTLMSSP or Kerberos, the structure is a SEC_WINNT_AUTH_IDENTITY or SEC_WINNT_AUTH_IDENTITY_EX structure. If the client
			/// obtains the credentials set on the proxy by calling CoQueryProxyBlanket, it must ensure that the memory remains valid and
			/// unchanged until a different identity is set on the proxy or all proxies on the object are released.
			/// </para>
			/// <para>
			/// If this parameter is <c>NULL</c>, COM uses the current proxy identity (which is either the process token or the
			/// impersonation token). If the handle refers to a structure, that identity is used.
			/// </para>
			/// <para>
			/// For Schannel, this parameter must either be a pointer to a CERT_CONTEXT structure that contains the client's X.509
			/// certificate, or <c>NULL</c> if the client wishes to make an anonymous connection to the server. If a certificate is
			/// specified, the caller must not free it as long as any proxy to the object exists in the current apartment.
			/// </para>
			/// <para>
			/// For Snego, this member is either <c>NULL</c>, points to a SEC_WINNT_AUTH_IDENTITY structure, or points to a
			/// SEC_WINNT_AUTH_IDENTITY_EX structure. If it is <c>NULL</c>, Snego will pick a list of authentication services based on those
			/// available on the client computer. If it points to a <c>SEC_WINNT_AUTH_IDENTITY_EX</c> structure, the structure's
			/// <c>PackageList</c> member must point to a string containing a comma-separated list of authentication service names and the
			/// <c>PackageListLength</c> member must give the number of bytes in the <c>PackageList</c> string. If <c>PackageList</c> is
			/// <c>NULL</c>, all calls using Snego will fail.
			/// </para>
			/// <para>
			/// If COLE_DEFAULT_AUTHINFO is specified, COM will pick the authentication information following its normal security blanket
			/// negotiation algorithm.
			/// </para>
			/// <para><c>SetBlanket</c> will return an error if both pAuthInfo is set and one of the cloaking flags is set in dwCapabilities.</para>
			/// </param>
			/// <param name="dwCapabilities">
			/// The capabilities of this proxy. Capability flags are defined in the EOLE_AUTHENTICATION_CAPABILITIES enumeration. The only
			/// flags that can be set through this method are EOAC_MUTUAL_AUTH, EOAC_STATIC_CLOAKING, EOAC_DYNAMIC_CLOAKING,
			/// EOAC_ANY_AUTHORITY (this flag is deprecated), EOAC_MAKE_FULLSIC, and EOAC_DEFAULT. Either EOAC_STATIC_CLOAKING or
			/// EOAC_DYNAMIC_CLOAKING can be set if pAuthInfo is not set and Schannel is not the authentication service. (See Cloaking for
			/// more information.) If any capability flags other than those mentioned here are indicated, <c>SetBlanket</c> will return an error.
			/// </param>
			/// <returns>
			/// <para>This method can return the following values.</para>
			/// <list type="table">
			/// <listheader>
			/// <term>Return code</term>
			/// <term>Description</term>
			/// </listheader>
			/// <item>
			/// <term>S_OK</term>
			/// <term>The method completed successfully.</term>
			/// </item>
			/// <item>
			/// <term>E_INVALIDARG</term>
			/// <term>One or more arguments are not valid.</term>
			/// </item>
			/// </list>
			/// </returns>
			/// <remarks>
			/// <para>
			/// <c>SetBlanket</c> sets the authentication information that will be used to make calls on the specified interface proxy. The
			/// values specified here override the values chosen by automatic security. Calling this method changes the security values for
			/// all other users of the specified proxy. If you want the changes to apply only to a particular instance of a proxy, call
			/// IClientSecurity::CopyProxy to make a private copy of the proxy and then call <c>SetBlanket</c> on the copy.
			/// </para>
			/// <para>
			/// Whenever this method is called, DCOM will set the identity on the proxy, and future calls made using this proxy will use
			/// this identity. Calls in progress when <c>SetBlanket</c> is called will use the authentication information on the proxy at
			/// the time the call was started. If pAuthInfo is <c>NULL</c>, the proxy identity defaults to the current process token (unless
			/// an authentication identity was specified on a call to CoInitializeSecurity). See Cloaking to learn how the cloaking flags
			/// affect the proxy when pAuthInfo is <c>NULL</c>.
			/// </para>
			/// <para>
			/// By default, COM will choose the first available authentication service and authorization service available on both the
			/// client and server computers and the principal name that the server registered for that authentication service. Currently,
			/// COM will not try another authentication service if the first fails.
			/// </para>
			/// <para>
			/// When the default constant for dwImpLevel is specified in <c>SetBlanket</c>, the parameter defaults to the value specified to
			/// CoInitializeSecurity. If <c>CoInitializeSecurity</c> is not called, it defaults to RPC_C_IMP_LEVEL_IDENTIFY.
			/// </para>
			/// <para>
			/// The initial value for dwAuthnLevel on a proxy will be the higher of the value set on the client's call to
			/// CoInitializeSecurity and the server's call to <c>CoInitializeSecurity</c>. For any process that did not call
			/// <c>CoInitializeSecurity</c>, the default authentication level is RPC_C_AUTHN_CONNECT.
			/// </para>
			/// <para>
			/// The default authentication and impersonation level for processes that do not call CoInitializeSecurity can be set with DCOMCNFG.
			/// </para>
			/// <para>
			/// If EOAC_DEFAULT is specified for dwCapabilities, the valid capabilities from CoInitializeSecurity will be used. If
			/// <c>CoInitializeSecurity</c> was not called, EOAC_NONE will be used for the capabilities flag.
			/// </para>
			/// <para>
			/// If <c>SetBlanket</c> is called simultaneously on two threads on the same proxy, only one set of changes will be applied. If
			/// <c>SetBlanket</c> and <c>CRpcOptions::Set</c> are called simultaneously on two threads on the same proxy, both changes may
			/// be applied or only one may be applied.
			/// </para>
			/// <para>
			/// Security information cannot be set on local interfaces such as the IClientSecurity interface. However, since that interface
			/// is only supported locally, there is no need for security. IUnknown and IMultiQI are special cases. The location
			/// implementation makes remote calls to support these interfaces. <c>SetBlanket</c> can be used for <c>IUnknown</c>.
			/// <c>IMultiQI</c> will use the security settings on <c>IUnknown</c>.
			/// </para>
			/// <para>
			/// To change one <c>SetBlanket</c> parameter without having to deal with the others, one can specify the default constants for
			/// the other parameters. Applications can change a parameter (such as the authentication level) and ignore the other
			/// parameters, including the authentication service, by setting all other parameters to the default constants.
			/// </para>
			/// <para>
			/// Note that it is important to set all unused parameters to the default constants because the default value is often not
			/// obvious. In particular, if you set the authentication service to the default, you should set the authentication information
			/// and principal name to the default. The reasons for this are twofold: First, the type of the authentication information
			/// depends on the authentication service DCOM chooses. Second, because DCOM needs to pass some complex authentication
			/// information for certain authentication services, if you set the authentication service to default and the authentication
			/// information to <c>NULL</c>, you might get a security setting that will not work.
			/// </para>
			/// </remarks>
			// https://docs.microsoft.com/en-us/windows/win32/api/objidl/nf-objidl-iclientsecurity-setblanket HRESULT SetBlanket( IUnknown
			// *pProxy, DWORD dwAuthnSvc, DWORD dwAuthzSvc, OLECHAR *pServerPrincName, DWORD dwAuthnLevel, DWORD dwImpLevel, void
			// *pAuthInfo, DWORD dwCapabilities );
			[PreserveSig]
			HRESULT SetBlanket([In, MarshalAs(UnmanagedType.IUnknown)] object pProxy, RPC_C_AUTHN dwAuthnSvc, RPC_C_AUTHZ dwAuthzSvc,
				[MarshalAs(UnmanagedType.LPWStr)] string pServerPrincName, RPC_C_AUTHN_LEVEL dwAuthnLevel, RPC_C_IMP_LEVEL dwImpLevel,
				[In, Optional] IntPtr pAuthInfo, EOLE_AUTHENTICATION_CAPABILITIES dwCapabilities);

			/// <summary>Makes a private copy of the proxy for the specified interface.</summary>
			/// <param name="pProxy">A pointer to the interface whose proxy is to be copied. This parameter cannot be <c>NULL</c>.</param>
			/// <param name="ppCopy">
			/// A pointer to the IUnknown interface pointer that receives the copy of the proxy. This parameter cannot be <c>NULL</c>.
			/// </param>
			/// <returns>
			/// <para>This method can return the following values.</para>
			/// <list type="table">
			/// <listheader>
			/// <term>Return code</term>
			/// <term>Description</term>
			/// </listheader>
			/// <item>
			/// <term>S_OK</term>
			/// <term>The method completed successfully.</term>
			/// </item>
			/// <item>
			/// <term>E_INVALIDARG</term>
			/// <term>One or more arguments are not valid.</term>
			/// </item>
			/// </list>
			/// </returns>
			/// <remarks>
			/// <para>
			/// <c>CopyProxy</c> is called by the client to make a private copy of the proxy for the specified interface. The proxy copy has
			/// default values for the authentication information. Its authentication information can be changed through a call to
			/// IClientSecurity::SetBlanket without affecting any other clients of the original proxy. The copy has one reference, and the
			/// caller of <c>CopyProxy</c> must ensure that the proxy copy gets freed.
			/// </para>
			/// <para>
			/// Local interfaces, such as IUnknown and IClientSecurity, cannot be copied. You cannot duplicate a proxy manager using <c>CopyProxy</c>.
			/// </para>
			/// <para>
			/// Copies of the same proxy have a special relationship with respect to QueryInterface. Given a proxy, a, of the IA interface
			/// of a remote object, suppose a copy of a is created, called b. In this case, calling <c>QueryInterface</c> from the b proxy
			/// for IID_IA will not retrieve the IA interface on b, but the one on a, the original proxy.
			/// </para>
			/// <para>
			/// Notice that anyone can query for a proxy and change security on it using SetBlanket. However, when you have made a copy of a
			/// proxy, no one can get the copy unless you give it to them. Only people who have the copy can set security on it.
			/// </para>
			/// <para>
			/// The helper function CoCopyProxy encapsulates a QueryInterface call for a pointer to IClientSecurity, a call to
			/// <c>CopyProxy</c> with the IClientSecurity pointer, and the release of the <c>IClientSecurity</c> pointer.
			/// </para>
			/// </remarks>
			// https://docs.microsoft.com/en-us/windows/win32/api/objidl/nf-objidl-iclientsecurity-copyproxy HRESULT CopyProxy( IUnknown
			// *pProxy, IUnknown **ppCopy );
			[PreserveSig]
			HRESULT CopyProxy([In, MarshalAs(UnmanagedType.IUnknown)] object pProxy, [MarshalAs(UnmanagedType.IUnknown)] out object ppCopy);
		}

		/// <summary>
		/// Enables you to obtain the following information about the apartment and thread that the caller is executing in: apartment type,
		/// thread type, and thread GUID. It also allows you to specify a thread GUID.
		/// </summary>
		/// <remarks>An instance of this interface for the current context can be obtained using CoGetObjectContext.</remarks>
		// https://docs.microsoft.com/en-us/windows/win32/api/objidl/nn-objidl-icomthreadinginfo
		[PInvokeData("objidl.h", MSDNShortId = "NN:objidl.IComThreadingInfo")]
		[ComImport, Guid("000001ce-0000-0000-C000-000000000046"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
		public interface IComThreadingInfo
		{
			/// <summary>Retrieves the type of apartment in which the caller is executing.</summary>
			/// <param name="pAptType">A points to an APTTYPE enumeration value that characterizes the caller's apartment.</param>
			/// <returns>
			/// <para>This method can return the following values.</para>
			/// <list type="table">
			/// <listheader>
			/// <term>Return code</term>
			/// <term>Description</term>
			/// </listheader>
			/// <item>
			/// <term>S_OK</term>
			/// <term>The method completed successfully.</term>
			/// </item>
			/// <item>
			/// <term>E_FAIL</term>
			/// <term>The caller is not executing in an apartment.</term>
			/// </item>
			/// </list>
			/// </returns>
			// https://docs.microsoft.com/en-us/windows/win32/api/objidl/nf-objidl-icomthreadinginfo-getcurrentapartmenttype HRESULT
			// GetCurrentApartmentType( APTTYPE *pAptType );
			[PreserveSig]
			HRESULT GetCurrentApartmentType(out APTTYPE pAptType);

			/// <summary>Retrieves the type of thread in which the caller is executing.</summary>
			/// <param name="pThreadType">A pointer to a THDTYPE enumeration value that characterizes the caller's thread.</param>
			/// <returns>
			/// <para>This method can return the following values.</para>
			/// <list type="table">
			/// <listheader>
			/// <term>Return code</term>
			/// <term>Description</term>
			/// </listheader>
			/// <item>
			/// <term>S_OK</term>
			/// <term>The method completed successfully.</term>
			/// </item>
			/// <item>
			/// <term>E_FAIL</term>
			/// <term>The caller is not executing in an apartment.</term>
			/// </item>
			/// </list>
			/// </returns>
			// https://docs.microsoft.com/en-us/windows/win32/api/objidl/nf-objidl-icomthreadinginfo-getcurrentthreadtype HRESULT
			// GetCurrentThreadType( THDTYPE *pThreadType );
			[PreserveSig]
			HRESULT GetCurrentThreadType(out THDTYPE pThreadType);

			/// <summary>Retrieves the GUID of the thread in which the caller is executing.</summary>
			/// <param name="pguidLogicalThreadId">A pointer to the GUID of the caller's thread.</param>
			/// <returns>
			/// <para>This method can return the following values.</para>
			/// <list type="table">
			/// <listheader>
			/// <term>Return code</term>
			/// <term>Description</term>
			/// </listheader>
			/// <item>
			/// <term>S_OK</term>
			/// <term>The method completed successfully.</term>
			/// </item>
			/// <item>
			/// <term>E_FAIL</term>
			/// <term>The caller is not executing in an apartment.</term>
			/// </item>
			/// </list>
			/// </returns>
			// https://docs.microsoft.com/en-us/windows/win32/api/objidl/nf-objidl-icomthreadinginfo-getcurrentlogicalthreadid HRESULT
			// GetCurrentLogicalThreadId( GUID *pguidLogicalThreadId );
			[PreserveSig]
			HRESULT GetCurrentLogicalThreadId(out Guid pguidLogicalThreadId);

			/// <summary>Sets the GUID of the thread in which the caller is executing.</summary>
			/// <param name="rguid">A reference to a GUID for the caller's thread.</param>
			/// <returns>
			/// <para>This method can return the following values.</para>
			/// <list type="table">
			/// <listheader>
			/// <term>Return code</term>
			/// <term>Description</term>
			/// </listheader>
			/// <item>
			/// <term>S_OK</term>
			/// <term>The method completed successfully.</term>
			/// </item>
			/// <item>
			/// <term>E_FAIL</term>
			/// <term>The caller is not executing in an apartment.</term>
			/// </item>
			/// </list>
			/// </returns>
			// https://docs.microsoft.com/en-us/windows/win32/api/objidl/nf-objidl-icomthreadinginfo-setcurrentlogicalthreadid HRESULT
			// SetCurrentLogicalThreadId( REFGUID rguid );
			[PreserveSig]
			HRESULT SetCurrentLogicalThreadId(in Guid rguid);
		}

		/// <summary>Supports setting COM+ context properties.</summary>
		/// <remarks>An instance of this interface for the current context can be obtained using CoGetObjectContext.</remarks>
		// https://docs.microsoft.com/en-us/windows/desktop/api/objidl/nn-objidl-icontext
		[PInvokeData("objidl.h", MSDNShortId = "89c41d9c-186c-4927-990d-92aa501f7d35")]
		[ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("000001c0-0000-0000-C000-000000000046")]
		public interface IContext
		{
			/// <summary>Adds the specified context property to the object context.</summary>
			/// <param name="rpolicyId">A GUID that uniquely identifies this context property.</param>
			/// <param name="flags">This parameter is reserved and must be zero.</param>
			/// <param name="pUnk">A pointer to the context property to be added.</param>
			// https://docs.microsoft.com/en-us/windows/desktop/api/objidl/nf-objidl-icontext-setproperty HRESULT SetProperty( REFGUID
			// rpolicyId, CPFLAGS flags, IUnknown *pUnk );
			void SetProperty(in Guid rpolicyId, [Optional] uint flags, [In, MarshalAs(UnmanagedType.IUnknown)] object pUnk);

			/// <summary>Removes the specified context property from the context.</summary>
			/// <param name="rPolicyId">The GUID that uniquely identifies the context property to be removed.</param>
			// https://docs.microsoft.com/en-us/windows/desktop/api/objidl/nf-objidl-icontext-removeproperty HRESULT RemoveProperty( REFGUID
			// rPolicyId );
			void RemoveProperty(in Guid rPolicyId);

			/// <summary>Retrieves the specified context property from the context.</summary>
			/// <param name="rGuid">The GUID that uniquely identifies the context property to be retrieved.</param>
			/// <param name="pFlags">The address of the variable that receives the flags associated with the property.</param>
			/// <returns>The address of the variable that receives the IUnknown interface pointer of the requested context property.</returns>
			// https://docs.microsoft.com/en-us/windows/desktop/api/objidl/nf-objidl-icontext-getproperty HRESULT GetProperty( REFGUID
			// rGuid, CPFLAGS *pFlags, IUnknown **ppUnk );
			[return: MarshalAs(UnmanagedType.IUnknown)]
			object GetProperty(in Guid rGuid, out uint pFlags);

			/// <summary>
			/// Returns an IEnumContextProps interface pointer that can be used to enumerate the context properties in this context.
			/// </summary>
			/// <returns>The address of the variable that receives the new IEnumContextProps interface pointer.</returns>
			// https://docs.microsoft.com/en-us/windows/desktop/api/objidl/nf-objidl-icontext-enumcontextprops HRESULT EnumContextProps(
			// IEnumContextProps **ppEnumContextProps );
			IEnumContextProps EnumContextProps();
		}

		/// <summary>Provides a mechanism for enumerating the context properties associated with a COM+ object context.</summary>
		// https://docs.microsoft.com/en-us/windows/desktop/api/objidl/nn-objidl-ienumcontextprops
		[PInvokeData("objidl.h", MSDNShortId = "64591e45-5478-4360-8c1f-08b09b5aef8e")]
		[ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("000001c1-0000-0000-C000-000000000046")]
		public interface IEnumContextProps : Vanara.Collections.ICOMEnum<ContextProperty>
		{
			/// <summary>Retrieves the specified number of items in the enumeration sequence.</summary>
			/// <param name="celt">
			/// The number of items to be retrieved. If there are fewer than the requested number of items left in the sequence, this method
			/// retrieves the remaining elements.
			/// </param>
			/// <param name="pContextProperties">
			/// <para>An array of enumerated items.</para>
			/// <para>
			/// The enumerator is responsible for allocating any memory, and the caller is responsible for freeing it. If celt is greater
			/// than 1, the caller must also pass a non-NULL pointer passed to pceltFetched to know how many pointers to release.
			/// </para>
			/// </param>
			/// <param name="pceltFetched">
			/// The number of items that were retrieved. This parameter is always less than or equal to the number of items requested.
			/// </param>
			/// <returns>If the method retrieves the number of items requested, the return value is S_OK. Otherwise, it is S_FALSE.</returns>
			// https://docs.microsoft.com/en-us/windows/desktop/api/objidl/nf-objidl-ienumcontextprops-next HRESULT Next( ULONG celt,
			// ContextProperty *pContextProperties, ULONG *pceltFetched );
			[PreserveSig]
			HRESULT Next(uint celt, [Out, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 0)] ContextProperty[] pContextProperties,
				 out uint pceltFetched);

			/// <summary>Skips over the specified number of items in the enumeration sequence.</summary>
			/// <param name="celt">The number of items to be skipped.</param>
			/// <returns>If the method skips the number of items requested, the return value is S_OK. Otherwise, it is S_FALSE.</returns>
			// https://docs.microsoft.com/en-us/windows/desktop/api/objidl/nf-objidl-ienumcontextprops-skip HRESULT Skip( ULONG celt );
			[PreserveSig]
			HRESULT Skip(uint celt);

			/// <summary>
			/// <para>Resets the enumeration sequence to the beginning.</para>
			/// </summary>
			/// <returns>
			/// <para>The return value is S_OK.</para>
			/// </returns>
			/// <remarks>
			/// <para>
			/// There is no guarantee that the same set of objects will be enumerated after the reset operation has completed. A static
			/// collection is reset to the beginning, but it can be too expensive for some collections, such as files in a directory, to
			/// guarantee this condition.
			/// </para>
			/// </remarks>
			// https://docs.microsoft.com/en-us/windows/desktop/api/objidl/nf-objidl-ienumcontextprops-reset HRESULT Reset( );
			void Reset();

			/// <summary>
			/// <para>Creates a new enumerator that contains the same enumeration state as the current one.</para>
			/// <para>
			/// This method makes it possible to record a point in the enumeration sequence in order to return to that point at a later
			/// time. The caller must release this new enumerator separately from the first enumerator.
			/// </para>
			/// </summary>
			/// <returns>A pointer to the cloned enumerator object.</returns>
			// https://docs.microsoft.com/en-us/windows/desktop/api/objidl/nf-objidl-ienumcontextprops-clone HRESULT Clone( IEnumContextProps
			// **ppEnumContextProps );
			IEnumContextProps Clone();

			/// <summary>Retrieves the number of context properties in the context.</summary>
			/// <returns>The count of items in the sequence.</returns>
			// https://docs.microsoft.com/en-us/windows/desktop/api/objidl/nf-objidl-ienumcontextprops-count HRESULT Count( ULONG *pcelt );
			uint Count();
		}

		/// <summary>
		/// Enumerate strings. <c>LPWSTR</c> is the type that indicates a pointer to a zero-terminated string of wide, or Unicode, characters.
		/// </summary>
		// https://docs.microsoft.com/en-us/windows/win32/api/objidl/nn-objidl-ienumstring
		[PInvokeData("objidl.h", MSDNShortId = "NN:objidl.IEnumString")]
		[ComImport, Guid("00000101-0000-0000-C000-000000000046"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
		public interface IEnumStringV : Vanara.Collections.ICOMEnum<string>
		{
			/// <summary>Retrieves the specified number of items in the enumeration sequence.</summary>
			/// <param name="celt">
			/// The number of items to be retrieved. If there are fewer than the requested number of items left in the sequence, this method
			/// retrieves the remaining elements.
			/// </param>
			/// <param name="rgelt">
			/// <para>An array of enumerated items.</para>
			/// <para>
			/// The enumerator is responsible for allocating any memory, and the caller is responsible for freeing it. If celt is greater
			/// than 1, the caller must also pass a non-NULL pointer passed to pceltFetched to know how many pointers to release.
			/// </para>
			/// </param>
			/// <param name="pceltFetched">
			/// The number of items that were retrieved. This parameter is always less than or equal to the number of items requested.
			/// </param>
			/// <returns>If the method retrieves the number of items requested, the return value is S_OK. Otherwise, it is S_FALSE.</returns>
			// https://docs.microsoft.com/en-us/windows/win32/api/objidl/nf-objidl-ienumstring-next HRESULT Next( ULONG celt, LPOLESTR
			// *rgelt, ULONG *pceltFetched );
			[PreserveSig]
			HRESULT Next(uint celt, [MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.LPWStr, SizeParamIndex = 0)] string[] rgelt, out uint pceltFetched);

			/// <summary>Skips over the specified number of items in the enumeration sequence.</summary>
			/// <param name="celt">The number of items to be skipped.</param>
			/// <returns>If the method skips the number of items requested, the return value is S_OK. Otherwise, it is S_FALSE.</returns>
			// https://docs.microsoft.com/en-us/windows/win32/api/objidl/nf-objidl-ienumstring-skip HRESULT Skip( ULONG celt );
			[PreserveSig]
			HRESULT Skip(uint celt);

			/// <summary>Resets the enumeration sequence to the beginning.</summary>
			/// <remarks>
			/// There is no guarantee that the same set of objects will be enumerated after the reset operation has completed. A static
			/// collection is reset to the beginning, but it can be too expensive for some collections, such as files in a directory, to
			/// guarantee this condition.
			/// </remarks>
			// https://docs.microsoft.com/en-us/windows/win32/api/objidl/nf-objidl-ienumstring-reset HRESULT Reset();
			void Reset();

			/// <summary>
			/// <para>Creates a new enumerator that contains the same enumeration state as the current one.</para>
			/// <para>
			/// This method makes it possible to record a point in the enumeration sequence in order to return to that point at a later
			/// time. The caller must release this new enumerator separately from the first enumerator.
			/// </para>
			/// </summary>
			/// <returns>A pointer to the cloned enumerator object.</returns>
			// https://docs.microsoft.com/en-us/windows/win32/api/objidl/nf-objidl-ienumstring-clone HRESULT Clone( IEnumString **ppenum );
			IEnumStringV Clone();
		}

		/// <summary>
		/// Manages a server object's count of marshaled, or external, connections. A server that maintains such a count can detect when it
		/// has no external connections and shut itself down in an orderly fashion.
		/// </summary>
		/// <remarks>
		/// <para>
		/// <c>IExternalConnection</c> is most commonly implemented on server objects, to enable the orderly shutdown of a link to an
		/// embedded object following a silent update. Objects that do not implement <c>IExternalConnection</c> risk losing data in such a
		/// situation: When the final link client releases the embedded (server) object, the last external connection on the object's stub
		/// manager is released, causing the stub manager to release its pointers to interfaces on the embedded object and initiate shutdown
		/// of the object. At this point, the server object calls IOleClientSite::SaveObject on the link container, and the link container's
		/// return call to IPersistStorage::Save fails because the stub manager no longer has a pointer to the embedded object. Any unsaved
		/// changes to the server object's data would then be lost.
		/// </para>
		/// <para>
		/// If the server object implements <c>IExternalConnection</c>, however, its stub manager will not release its connection to the
		/// object when the last external connection is released. Instead, it will stay connected until the object is ready to destroy itself.
		/// </para>
		/// <para>
		/// In standard marshaling, to increment the object's count of external connections, COM calls IExternalConnection::AddConnection on
		/// the object when the object is first marshaled. The stub manager calls the methods of <c>IExternalConnection</c> on the object as
		/// subsequent external connections are obtained and released. When the object's count of external connections goes to zero, the
		/// object can save its data and then revoke itself from the running object table and do whatever else is necessary to reduce its
		/// object reference count to zero.
		/// </para>
		/// <para>
		/// An object that implements <c>IExternalConnection</c> should explicitly call CoDisconnectObject on itself when its external
		/// reference count drops to 0. This call will cause the stub manager to call Release on the object so that the object can destroy itself.
		/// </para>
		/// </remarks>
		// https://docs.microsoft.com/en-us/windows/win32/api/objidl/nn-objidl-iexternalconnection
		[PInvokeData("objidl.h", MSDNShortId = "NN:objidl.IExternalConnection")]
		[ComImport, Guid("00000019-0000-0000-C000-000000000046"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
		public interface IExternalConnection
		{
			/// <summary>Increments the count of an object's strong external connections.</summary>
			/// <param name="extconn">
			/// The type of external connection to the object. The only type of external connection currently supported by this interface is
			/// strong, which means that the object must remain alive as long as this external connection exists. Strong external
			/// connections are represented by the value EXTCONN_STRONG, which is defined in the enumeration EXTCONN.
			/// </param>
			/// <param name="reserved">
			/// Information about the connection. This parameter is reserved for use by OLE. Its value can be zero, but not necessarily.
			/// Therefore, implementations of <c>AddConnection</c> should not contain blocks of code whose execution depends on whether a
			/// zero value is returned.
			/// </param>
			/// <returns>The method returns the count of connections. This value is intended to be used only for debugging purposes.</returns>
			/// <remarks>
			/// <para>
			/// An object created by a EXE object server relies on its stub manager to call <c>AddConnection</c> whenever a link client
			/// activates and therefore creates an external lock on the object. When the link client breaks the connection, the stub manager
			/// calls IExternalConnection::ReleaseConnection to release the lock.
			/// </para>
			/// <para>
			/// DLL object applications exist in the same process space as their objects, so they do not use RPC (remote procedure calls)
			/// and do not have stub managers to keep track of external connections. Therefore, DLL servers that support external links to
			/// their objects must implement IExternalConnection so that link clients can directly call the interface to inform them when
			/// connections are added or released.
			/// </para>
			/// <para>The following is a typical implementation for the <c>AddConnection</c> method.</para>
			/// <para>
			/// <code>DWORD MyInterface::AddConnection(DWORD extconn, DWORD dwReserved) { return extconn &amp; EXTCONN_STRONG ? ++m_cStrong : 0; }</code>
			/// </para>
			/// </remarks>
			// https://docs.microsoft.com/en-us/windows/win32/api/objidl/nf-objidl-iexternalconnection-addconnection DWORD AddConnection(
			// DWORD extconn, DWORD reserved );
			[PreserveSig]
			uint AddConnection(EXTCONN extconn, [In, Optional] uint reserved);

			/// <summary>Decrements the count of an object's strong external connections.</summary>
			/// <param name="extconn">
			/// The type of external connection to the object. The only type of external connection currently supported by this interface is
			/// strong, which means that the object must remain alive as long as this external connection exists. Strong external
			/// connections are represented by the value EXTCONN_STRONG, which is defined in the enumeration EXTCONN.
			/// </param>
			/// <param name="reserved">
			/// Information about the connection. This parameter is reserved for use by OLE. Its value can be zero, but not necessarily.
			/// Therefore, implementations of <c>ReleaseConnection</c> should not contain blocks of code whose execution depends on whether
			/// a zero value is returned.
			/// </param>
			/// <param name="fLastReleaseCloses">
			/// This parameter is <c>TRUE</c> if the connection being released is the last external lock on the object, and therefore the
			/// object should close. Otherwise, the object should remain open until closed by the user or another process.
			/// </param>
			/// <returns>The method returns the count of connections. This value is intended to be used only for debugging purposes.</returns>
			/// <remarks>
			/// If fLastReleaseCloses equals <c>TRUE</c>, calling <c>ReleaseConnection</c> causes the object to shut itself down. Calling
			/// this method is the only way in which a DLL object, running in the same process space as the container application, will know
			/// when to close following a silent update.
			/// </remarks>
			// https://docs.microsoft.com/en-us/windows/win32/api/objidl/nf-objidl-iexternalconnection-releaseconnection DWORD
			// ReleaseConnection( DWORD extconn, DWORD reserved, BOOL fLastReleaseCloses );
			[PreserveSig]
			uint ReleaseConnection(EXTCONN extconn, [Optional] uint reserved, [MarshalAs(UnmanagedType.Bool)] bool fLastReleaseCloses);
		}

		/// <summary>Marks an interface as eligible for fast rundown behavior.</summary>
		/// <remarks>
		/// <para>
		/// A Component Object Model (COM) object implements the <c>IFastRundown</c> marker interface to opt into the fast rundown behavior.
		/// </para>
		/// <para>
		/// All Windows Store app processes, as well as the broker processes RuntimeBroker.exe and PickerHost.exe, apply fast rundown at the
		/// process level, which means that all objects in any of these processes are subjected to fast rundown automatically. Desktop
		/// processes don't get this behavior by default and must opt in at the process level. Specific objects opt in by implementing the
		/// <c>IFastRundown</c> marker interface.
		/// </para>
		/// </remarks>
		// https://docs.microsoft.com/en-us/windows/win32/api/objidl/nn-objidl-ifastrundown
		[PInvokeData("objidl.h", MSDNShortId = "NN:objidl.IFastRundown")]
		[ComImport, Guid("00000040-0000-0000-C000-000000000046"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
		public interface IFastRundown
		{
		}

		/// <summary>
		/// Enables any apartment in a process to get access to an interface implemented on an object in any other apartment in the process.
		/// </summary>
		/// <remarks>
		/// <para>
		/// The <c>IGlobalInterfaceTable</c> interface is an efficient way for a process to store an interface pointer in a memory location
		/// that can be accessed from multiple apartments within the process, such as processwide variables and agile (free-threaded
		/// marshaled) objects containing interface pointers to other objects.
		/// </para>
		/// <para>
		/// An agile object is unaware of the underlying COM infrastructure in which it runsâ€”in other words, what apartment, context, and
		/// thread it is executing on. The object may be holding on to interfaces that are specific to an apartment or context. For this
		/// reason, calling these interfaces from wherever the agile component is executing may not always work properly. The global
		/// interface table avoids this problem by guaranteeing that a valid proxy (or direct pointer) to the object is used, based on where
		/// the agile object is executing.
		/// </para>
		/// <para>
		/// The global interface table is not portable across process or machine boundaries, so it cannot be used in place of the normal
		/// parameter-passing mechanism.
		/// </para>
		/// </remarks>
		// https://docs.microsoft.com/en-us/windows/win32/api/objidl/nn-objidl-iglobalinterfacetable
		[PInvokeData("objidl.h", MSDNShortId = "NN:objidl.IGlobalInterfaceTable")]
		[ComImport, Guid("00000146-0000-0000-C000-000000000046"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
		public interface IGlobalInterfaceTable
		{
			/// <summary>
			/// Registers the specified interface on an object residing in one apartment of a process as a global interface, enabling other
			/// apartments access to that interface.
			/// </summary>
			/// <param name="pUnk">
			/// An interface pointer of type riid on the object on which the interface to be registered as global is implemented.
			/// </param>
			/// <param name="riid">The IID of the interface to be registered as global.</param>
			/// <param name="pdwCookie">
			/// An identifier that can be used by another apartment to get access to a pointer to the interface being registered. The value
			/// of an invalid cookie is 0.
			/// </param>
			/// <returns>
			/// <para>This method can return the following values.</para>
			/// <list type="table">
			/// <listheader>
			/// <term>Return code</term>
			/// <term>Description</term>
			/// </listheader>
			/// <item>
			/// <term>S_OK</term>
			/// <term>The method completed successfully.</term>
			/// </item>
			/// <item>
			/// <term>E_INVALIDARG</term>
			/// <term>One or more parameters are invalid.</term>
			/// </item>
			/// </list>
			/// </returns>
			/// <remarks>
			/// <para>
			/// Called in the apartment in which an object resides to register one of the object's interfaces as a global interface. This
			/// method supplies a pointer to a cookie that other apartments can use in a call to the GetInterfaceFromGlobal method to get a
			/// pointer to that interface.
			/// </para>
			/// <para>
			/// The interface pointer may be a pointer to an in-process object, or it may be a pointer to a proxy for an object residing in
			/// another apartment, in another process, or on another computer.
			/// </para>
			/// <para>The apartment that calls this method must remain alive until the corresponding call to RevokeInterfaceFromGlobal.</para>
			/// </remarks>
			// https://docs.microsoft.com/en-us/windows/win32/api/objidl/nf-objidl-iglobalinterfacetable-registerinterfaceinglobal HRESULT
			// RegisterInterfaceInGlobal( IUnknown *pUnk, REFIID riid, DWORD *pdwCookie );
			[PreserveSig]
			HRESULT RegisterInterfaceInGlobal([In, MarshalAs(UnmanagedType.IUnknown, IidParameterIndex = 1)] object pUnk, in Guid riid, out uint pdwCookie);

			/// <summary>Revokes the registration of an interface in the global interface table.</summary>
			/// <param name="dwCookie">Identifies the interface whose global registration is to be revoked.</param>
			/// <returns>
			/// <para>This method can return the following values.</para>
			/// <list type="table">
			/// <listheader>
			/// <term>Return code</term>
			/// <term>Description</term>
			/// </listheader>
			/// <item>
			/// <term>S_OK</term>
			/// <term>The method completed successfully.</term>
			/// </item>
			/// <item>
			/// <term>E_INVALIDARG</term>
			/// <term>The parameter is invalid.</term>
			/// </item>
			/// </list>
			/// </returns>
			/// <remarks>
			/// Call this method when an interface registered in the global interface table object no longer needs to be accessed by other
			/// apartments in the same process. This method can be called by any apartment in the process, including apartments other than
			/// the one that registered the interface in the global interface table.
			/// </remarks>
			// https://docs.microsoft.com/en-us/windows/win32/api/objidl/nf-objidl-iglobalinterfacetable-revokeinterfacefromglobal HRESULT
			// RevokeInterfaceFromGlobal( DWORD dwCookie );
			[PreserveSig]
			HRESULT RevokeInterfaceFromGlobal([In] uint dwCookie);

			/// <summary>
			/// Retrieves a pointer to an interface on an object that is usable by the calling apartment. This interface must be currently
			/// registered in the global interface table.
			/// </summary>
			/// <param name="dwCookie">Identifies the interface (and its object), and is retrieved through a call to IGlobalInterfaceTable::RegisterInterfaceInGlobal.</param>
			/// <param name="riid">The IID of the interface.</param>
			/// <param name="ppv">A pointer to the pointer for the requested interface.</param>
			/// <returns>
			/// <para>This method can return the following values.</para>
			/// <list type="table">
			/// <listheader>
			/// <term>Return code</term>
			/// <term>Description</term>
			/// </listheader>
			/// <item>
			/// <term>S_OK</term>
			/// <term>The method completed successfully.</term>
			/// </item>
			/// <item>
			/// <term>E_INVALIDARG</term>
			/// <term>One or more parameters are invalid.</term>
			/// </item>
			/// </list>
			/// </returns>
			/// <remarks>
			/// <para>
			/// After an interface has been registered in the global interface table, an apartment can get a pointer to this interface by
			/// calling the <c>GetInterfaceFromGlobal</c> method with the supplied cookie. This pointer to the interface can be used in the
			/// calling apartment but not by other apartments in the process.
			/// </para>
			/// <para>
			/// The application is responsible for coordinating access to the global variable during calls to
			/// IGlobalInterfaceTable::RevokeInterfaceFromGlobal. That is, the application should ensure that one thread does not call
			/// <c>RevokeInterfaceFromGlobal</c> while another thread is calling <c>GetInterfaceFromGlobal</c> with the same cookie.
			/// Multiple calls to <c>GetInterfaceFromGlobal</c> for the same cookie are permitted.
			/// </para>
			/// <para>
			/// The <c>GetInterfaceFromGlobal</c> method calls AddRef on the pointer obtained in the ppv parameter. It is the caller's
			/// responsibility to call Release on this pointer.
			/// </para>
			/// </remarks>
			// https://docs.microsoft.com/en-us/windows/win32/api/objidl/nf-objidl-iglobalinterfacetable-getinterfacefromglobal HRESULT
			// GetInterfaceFromGlobal( DWORD dwCookie, REFIID riid, void **ppv );
			[PreserveSig]
			HRESULT GetInterfaceFromGlobal([In] uint dwCookie, in Guid riid, [MarshalAs(UnmanagedType.IUnknown, IidParameterIndex = 1)] out object ppv);
		}

		/// <summary>Sets and queries global properties of the Component Object Model (COM) runtime.</summary>
		/// <remarks>
		/// <para>The following global properties of the COM runtime can be set and queried with this interface.</para>
		/// <list type="table">
		/// <listheader>
		/// <term>Property</term>
		/// <term>Values</term>
		/// </listheader>
		/// <item>
		/// <term>COMGLB_APPID</term>
		/// <term>The AppID for the process. This is the only supported property on Windows XP.</term>
		/// </item>
		/// <item>
		/// <term>COMGLB_EXCEPTION_HANDLING</term>
		/// <term>
		/// Possible values for the COMGLB_EXCEPTION_HANDLING property are: By default, the COM runtime handles fatal exceptions raised
		/// during method invocations by returning the RPC_E_SERVERFAULT error code to the client. An application disables this behavior to
		/// allow exceptions to propagate to WER, which creates application process dumps and terminates the application. This prevents
		/// possible data corruption and allows an application vendor to debug the dumps. For new applications, it is recommended that the
		/// COMGLB_EXCEPTION_HANDLING property be set to COMGLB_EXCEPTION_DONOT_HANDLE_ANY.
		/// </term>
		/// </item>
		/// <item>
		/// <term>COMGLB_RPC_THREADPOOL_SETTING</term>
		/// <term>
		/// Possible values for the COMGLB_RPC_THREADPOOL_SETTING property in the Set method are: Possible values for the
		/// COMGLB_RPC_THREADPOOL_SETTING property in the Query method are: RPC uses the system thread pool by default in Windows 7. Since
		/// the system thread pool is shared by multiple components in the process, COM and RPC operations may behave incorrectly if the
		/// thread pool state is corrupted by a component. The COMGLB_RPC_THREADPOOL_SETTING property can be used to change the RPC thread
		/// pool behavior. Changing the default behavior will incur a performance penalty since this causes RPC to use an extra thread.
		/// Therefore, care should be exercised when changing this setting. It is recommended that this setting is changed only for
		/// application compatibility reasons. Note This property is only supported in Windows 7 and later versions of Windows.
		/// </term>
		/// </item>
		/// <item>
		/// <term>COMGLB_RO_SETTINGS</term>
		/// <term>
		/// Possible values for the COMGLB_RO_SETTINGS property are: Note This property is only supported in Windows 8 and later versions of Windows.
		/// </term>
		/// </item>
		/// <item>
		/// <term>COMGLB_UNMARSHALING_POLICY</term>
		/// <term>
		/// Possible values for the COMGLB_UNMARSHALING_POLICY property are: Note This property is only supported in Windows 8 and later
		/// versions of Windows.
		/// </term>
		/// </item>
		/// </list>
		/// <para>
		/// It's important for applications that detect crashes and other exceptions that might be generated while executing inbound COM
		/// calls, for example a call on a local server or when executing the IDropTarget::Drop method, to set COMGLB_EXCEPTION_HANDLING to
		/// COMGLB_EXCEPTION_DONOT_HANDLE to disable COM behavior of catching exceptions. Failure to do this can lead to corrupt process
		/// state, for example locks held when these exceptions are thrown are abandoned, and the process could enter an inconsistent state.
		/// </para>
		/// <para>All such applications should execute this code at startup.</para>
		/// <para>
		/// <code> IGlobalOptions *pGlobalOptions; hr = CoCreateInstance(CLSID_GlobalOptions, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&amp;pGlobalOptions)); if (SUCCEEDED(hr)) { hr = pGlobalOptions-&gt;Set(COMGLB_EXCEPTION_HANDLING, COMGLB_EXCEPTION_DONOT_HANDLE); pGlobalOptions-&gt;Release(); }</code>
		/// </para>
		/// </remarks>
		// https://docs.microsoft.com/en-us/windows/win32/api/objidlbase/nn-objidlbase-iglobaloptions
		[PInvokeData("objidlbase.h", MSDNShortId = "NN:objidlbase.IGlobalOptions")]
		[ComImport, Guid("0000015B-0000-0000-C000-000000000046"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
		public interface IGlobalOptions
		{
			/// <summary>Sets the specified global property of the COM runtime.</summary>
			/// <param name="dwProperty">
			/// The global property of the COM runtime. For a list of properties that can be set with this method, see IGlobalOptions.
			/// </param>
			/// <param name="dwValue">The value of the property.</param>
			/// <returns>The return value is S_OK if the property was set successfully.</returns>
			// https://docs.microsoft.com/en-us/windows/win32/api/objidl/nf-objidl-iglobaloptions-set HRESULT Set( GLOBALOPT_PROPERTIES
			// dwProperty, ULONG_PTR dwValue );
			[PreserveSig]
			HRESULT Set([In] GLOBALOPT_PROPERTIES dwProperty, [In] IntPtr dwValue);

			/// <summary>Queries the specified global property of the COM runtime.</summary>
			/// <param name="dwProperty">
			/// The global property of the COM runtime. For a list of properties that can be set with this method, see IGlobalOptions.
			/// </param>
			/// <param name="pdwValue">The value of the property.</param>
			/// <returns>The return value is S_OK if the property is queried successfully.</returns>
			// https://docs.microsoft.com/en-us/windows/win32/api/objidlbase/nf-objidlbase-iglobaloptions-query HRESULT Query(
			// GLOBALOPT_PROPERTIES dwProperty, ULONG_PTR *pdwValue );
			[PreserveSig]
			HRESULT Query([In] GLOBALOPT_PROPERTIES dwProperty, out IntPtr pdwValue);
		}

		/// <summary>
		/// Used exclusively in lightweight client-side handlers that require access to some of the internal interfaces on the proxy.
		/// </summary>
		/// <remarks>
		/// <para>
		/// Handlers that need access to some of the internal interfaces on the proxy manager have to go through the <c>IInternalUnknown</c>
		/// interface. This prevents the handlers from blindly delegating and exposing the aggregatee's internal interfaces outside of the
		/// aggregate. These interfaces include IClientSecurity and IMultiQI. If the handler wants to expose <c>IClientSecurity</c> or
		/// <c>IMultiQI</c>, the handler should implement these interfaces itself and delegate to the proxy manager's implementation of
		/// these interfaces when appropriate.
		/// </para>
		/// <para>
		/// For the IClientSecurity interface, if the client tries to set the security on an interface that the handler has exposed, the
		/// handler should set the security on the underlying network interface proxy.
		/// </para>
		/// <para>
		/// For the IMultiQI interface, the handler should fill in the interfaces it knows about and then forward the call to the proxy
		/// manager to fill in the rest of the interfaces.
		/// </para>
		/// </remarks>
		// https://docs.microsoft.com/en-us/windows/win32/api/objidlbase/nn-objidlbase-iinternalunknown
		[PInvokeData("objidlbase.h", MSDNShortId = "NN:objidlbase.IInternalUnknown")]
		[ComImport, Guid("00000021-0000-0000-C000-000000000046"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
		public interface IInternalUnknown
		{
			/// <summary>Retrieves pointers to the supported internal interfaces on an object.</summary>
			/// <param name="riid">The identifier of the internal interface being requested.</param>
			/// <param name="ppv">
			/// The address of a pointer variable that receives the interface pointer requested in the riid parameter. Upon successful
			/// return, *ppv contains the requested interface pointer to the object. If the object does not support the interface, *ppv is
			/// set to <c>NULL</c>.
			/// </param>
			/// <returns>This method returns S_OK if the interface is supported, and E_NOINTERFACE otherwise.</returns>
			/// <remarks>
			/// This method is similar to the IUnknown::QueryInterface method, except that the COM proxy manager, when aggregated, will not
			/// expose some interfaces through <c>QueryInterface</c>. Instead, those internal interfaces must be exposed through <c>QueryInternalInterface</c>.
			/// </remarks>
			// https://docs.microsoft.com/en-us/windows/win32/api/objidlbase/nf-objidlbase-iinternalunknown-queryinternalinterface HRESULT
			// QueryInternalInterface( REFIID riid, void **ppv );
			[PreserveSig]
			HRESULT QueryInternalInterface(in Guid riid, [MarshalAs(UnmanagedType.IUnknown, IidParameterIndex = 0)] out object ppv);
		}

		/// <summary>Allocates, frees, and manages memory.</summary>
		// https://docs.microsoft.com/en-us/windows/desktop/api/objidl/nn-objidl-imalloc
		[PInvokeData("objidl.h", MSDNShortId = "047f281e-2665-4d6d-9a0b-918cd3339447")]
		[ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("00000002-0000-0000-C000-000000000046")]
		public interface IMalloc
		{
			/// <summary>Allocates a block of memory.</summary>
			/// <param name="cb">The size of the memory block to be allocated, in bytes.</param>
			/// <returns>
			/// <para>If the method succeeds, the return value is a pointer to the allocated block of memory. Otherwise, it is <c>NULL</c>.</para>
			/// <para>
			/// Applications should always check the return value from this method, even when requesting small amounts of memory, because
			/// there is no guarantee the memory will be allocated.
			/// </para>
			/// </returns>
			/// <remarks>
			/// <para>
			/// The initial contents of the returned memory block are undefined, there is no guarantee that the block has been initialized,
			/// so you should initialize it in your code. The allocated block may be larger than cb bytes because of the space required for
			/// alignment and for maintenance information.
			/// </para>
			/// <para>
			/// If cb is zero, <c>Alloc</c> allocates a zero-length item and returns a valid pointer to that item. If there is insufficient
			/// memory available, <c>Alloc</c> returns <c>NULL</c>.
			/// </para>
			/// </remarks>
			// https://docs.microsoft.com/en-us/windows/desktop/api/objidl/nf-objidl-imalloc-alloc void * Alloc( SIZE_T cb );
			[PreserveSig]
			IntPtr Alloc(SizeT cb);

			/// <summary>Changes the size of a previously allocated block of memory.</summary>
			/// <param name="pv">
			/// A pointer to the block of memory to be reallocated. This parameter can be <c>NULL</c>, as discussed in the Remarks section below.
			/// </param>
			/// <param name="cb">
			/// The size of the memory block to be reallocated, in bytes. This parameter can be 0, as discussed in the Remarks section below.
			/// </param>
			/// <returns>If the method succeeds, the return value is a pointer to the reallocated block of memory. Otherwise, it is <c>NULL</c>.</returns>
			/// <remarks>
			/// <para>
			/// This method reallocates a block of memory, but does not guarantee that its contents are initialized. Therefore, the caller
			/// is responsible for subsequently initializing the memory. The allocated block may be larger than cb bytes because of the
			/// space required for alignment and for maintenance information.
			/// </para>
			/// <para>
			/// The pv argument points to the beginning of the block. If pv is <c>NULL</c>, <c>Realloc</c> allocates a new memory block in
			/// the same way that IMalloc::Alloc does. If pv is not <c>NULL</c>, it should be a pointer returned by a prior call to <c>Alloc</c>.
			/// </para>
			/// <para>
			/// The cb argument specifies the size of the new block, in bytes. The contents of the block are unchanged up to the shorter of
			/// the new and old sizes, although the new block can be in a different location. Because the new block can be in a different
			/// memory location, the pointer returned by <c>Realloc</c> is not guaranteed to be the pointer passed through the pv argument.
			/// If pv is not <c>NULL</c> and cb is zero, the memory pointed to by pv is freed.
			/// </para>
			/// <para>
			/// <c>Realloc</c> returns a void pointer to the reallocated (and possibly moved) block of memory. The return value is
			/// <c>NULL</c> if the size is zero and the buffer argument is not <c>NULL</c>, or if there is not enough memory available to
			/// expand the block to the specified size. In the first case, the original block is freed; in the second, the original block is unchanged.
			/// </para>
			/// <para>
			/// The storage space pointed to by the return value is guaranteed to be suitably aligned for storage of any type of object. To
			/// get a pointer to a type other than <c>void</c>, use a type cast on the return value.
			/// </para>
			/// </remarks>
			// https://docs.microsoft.com/en-us/windows/desktop/api/objidl/nf-objidl-imalloc-realloc void * Realloc( void *pv, SIZE_T cb );
			[PreserveSig]
			IntPtr Realloc([In, Optional] IntPtr pv, SizeT cb);

			/// <summary>Frees a previously allocated block of memory.</summary>
			/// <param name="pv">A pointer to the memory block to be freed. If this parameter is <c>NULL</c>, this method has no effect.</param>
			/// <remarks>
			/// This method frees a block of memory previously allocated through a call to IMalloc::Alloc or IMalloc::Realloc. The number of
			/// bytes freed equals the number of bytes that were allocated. After the call, the block of memory pointed to by pv is invalid
			/// and can no longer be used.
			/// </remarks>
			// https://docs.microsoft.com/en-us/windows/desktop/api/objidl/nf-objidl-imalloc-free void Free( void *pv );
			[PreserveSig]
			void Free([In, Optional] IntPtr pv);

			/// <summary>Retrieves the size of a previously allocated block of memory.</summary>
			/// <param name="pv">A pointer to the block of memory.</param>
			/// <returns>The size of the allocated memory block in bytes or, if pv is a <c>NULL</c> pointer, -1.</returns>
			/// <remarks>
			/// To get the size in bytes of a memory block, the block must have been previously allocated with IMalloc::Alloc or
			/// IMalloc::Realloc. The size returned is the actual size of the allocation, which may be greater than the size requested when
			/// the allocation was made.
			/// </remarks>
			// https://docs.microsoft.com/en-us/windows/desktop/api/objidl/nf-objidl-imalloc-getsize SIZE_T GetSize( void *pv );
			[PreserveSig]
			SizeT GetSize([In, Optional] IntPtr pv);

			/// <summary>Determines whether this allocator was used to allocate the specified block of memory.</summary>
			/// <param name="pv">A pointer to the block of memory. If this parameter is a <c>NULL</c> pointer, -1 is returned.</param>
			/// <returns>
			/// <para>This method can return the following values.</para>
			/// <list type="table">
			/// <listheader>
			/// <term>Return value</term>
			/// <term>Description</term>
			/// </listheader>
			/// <item>
			/// <term>1</term>
			/// <term>The block of memory was allocated by this allocator.</term>
			/// </item>
			/// <item>
			/// <term>0</term>
			/// <term>The block of memory was not allocated by this allocator.</term>
			/// </item>
			/// <item>
			/// <term>-1</term>
			/// <term>This method cannot determine whether this allocator allocated the block of memory.</term>
			/// </item>
			/// </list>
			/// </returns>
			// https://docs.microsoft.com/en-us/windows/desktop/api/objidl/nf-objidl-imalloc-didalloc int DidAlloc( void *pv );
			[PreserveSig]
			int DidAlloc([In, Optional] IntPtr pv);

			/// <summary>
			/// Minimizes the heap as much as possible by releasing unused memory to the operating system, coalescing adjacent free blocks,
			/// and committing free pages.
			/// </summary>
			// https://docs.microsoft.com/en-us/windows/desktop/api/objidl/nf-objidl-imalloc-heapminimize void HeapMinimize( );
			[PreserveSig]
			void HeapMinimize();
		}

		/// <summary>Enables a COM object to define and manage the marshaling of its interface pointers.</summary>
		/// <remarks>
		/// <para>
		/// Marshaling is the process of packaging data into packets for transmission to a different process or computer. Unmarshaling is
		/// the process of recovering that data at the receiving end. In any given call, method arguments are marshaled and unmarshaled in
		/// one direction, while return values are marshaled and unmarshaled in the other.
		/// </para>
		/// <para>
		/// Although marshaling applies to all data types, interface pointers require special handling. The fundamental problem is how
		/// client code running in one address space can correctly dereference a pointer to an interface on an object residing in a
		/// different address space. The COM solution is for a client application to communicate with the original object through a
		/// surrogate object, or proxy, which lives in the client's process. The proxy holds a reference to an interface on the original
		/// object and hands the client a pointer to an interface on itself. When the client calls an interface method on the original
		/// object, its call is actually going to the proxy. Therefore, from the client's point of view, all calls are in-process.
		/// </para>
		/// <para>
		/// On receiving a call, the proxy marshals the method arguments and through some means of interprocess communication, such as RPC,
		/// passes them along to code in the server process, which unmarshals the arguments and passes them to the original object. This
		/// same code marshals return values for transmission back to the proxy, which unmarshals the values and passes them to the client application.
		/// </para>
		/// <para>
		/// <c>IMarshal</c> provides methods for creating, initializing, and managing a proxy in a client process; it does not dictate how
		/// the proxy should communicate with the original object. The COM default implementation of <c>IMarshal</c> uses RPC. When you
		/// implement this interface yourself, you are free to choose any method of interprocess communication you deem to be appropriate
		/// for your application—shared memory, named pipe, window handle, RPC—in short, whatever works.
		/// </para>
		/// <para>IMarshal Default Implementation</para>
		/// <para>
		/// COM uses its own internal implementation of the <c>IMarshal</c> interface to marshal any object that does not provide its own
		/// implementation. COM makes this determination by querying the object for <c>IMarshal</c>. If the interface is missing, COM
		/// defaults to its internal implementation.
		/// </para>
		/// <para>
		/// The COM default implementation of <c>IMarshal</c> uses a generic proxy for each object and creates individual stubs and proxies,
		/// as they are needed, for each interface implemented on the object. This mechanism is necessary because COM cannot know in advance
		/// what particular interfaces a given object may implement. Developers who do not use COM default marshaling, electing instead to
		/// write their own proxy and marshaling routines, know at compile time all the interfaces to be found on their objects and
		/// therefore understand exactly what marshaling code is required. COM, in providing marshaling support for all objects, must do so
		/// at run time.
		/// </para>
		/// <para>
		/// The interface proxy resides in the client process; the interface stub resides in the server. Together, each pair handles all
		/// marshaling for the interface. The job of each interface proxy is to marshal arguments and unmarshal return values and out
		/// parameters that are passed back and forth in subsequent calls to its interface. The job of each interface stub is to unmarshal
		/// function arguments and pass them along to the original object and then marshal the return values and out parameters that the
		/// object returns.
		/// </para>
		/// <para>
		/// Proxy and stub communicate by means of an RPC (remote procedure call) channel, which utilizes the system's RPC infrastructure
		/// for interprocess communication. The RPC channel implements a single interface, IRpcChannelBuffer, to which both interface
		/// proxies and stubs hold a pointer. The proxy and stub call the interface to obtain a marshaling packet, send the data to their
		/// counterpart, and destroy the packet when they are done. The interface stub also holds a pointer to the original object.
		/// </para>
		/// <para>
		/// For any given interface, the proxy and stub are both implemented as instances of the same class, which is listed for each
		/// interface in the system registry under the label <c>ProxyStubClsid32</c>. This entry maps the interface's IID to the
		/// <c>CLSID</c> of its proxy and stub objects. When COM needs to marshal an interface, it looks in the system registry to obtain
		/// the appropriate <c>CLSID</c>. The server identified by this <c>CLSID</c> implements both the interface proxy and interface stub.
		/// </para>
		/// <para>
		/// Most often, the class to which this <c>CLSID</c> refers is automatically generated by a tool whose input is a description of the
		/// function signatures and semantics of a given interface, written in some interface description language. While using such a
		/// language is highly recommended and encouraged for accuracy's sake, doing so is not required. Proxies and stubs are merely COM
		/// components used by the RPC infrastructure and, as such, can be written in any manner desired, as long as the correct external
		/// contracts are upheld. The programmer who designs a new interface is responsible for ensuring that all interface proxies and
		/// stubs that ever exist agree on the representation of their marshaled data.
		/// </para>
		/// <para>
		/// When created, interface proxies are always aggregated into a larger proxy, which represents the object as a whole. This object
		/// proxy also aggregates the COM generic proxy object, which is known as the proxy manager. The proxy manager implements two
		/// interfaces: IUnknown and <c>IMarshal</c>. All of the other interfaces that may be implemented on an object are exposed in its
		/// object proxy through the aggregation of individual interface proxies. A client holding a pointer to the object proxy "believes"
		/// it holds a pointer to the actual object.
		/// </para>
		/// <para>
		/// A proxy representing the object as a whole is required in the client process so that a client can distinguish calls to the same
		/// interfaces implemented on entirely different objects. Such a requirement does not exist in the server process, however, where
		/// the object itself resides, because all interface stubs communicate only with the objects for which they were created. No other
		/// connection is possible.
		/// </para>
		/// <para>
		/// Interface stubs, by contrast with interface proxies, are not aggregated because there is no need that they appear to some
		/// external client to be part of a larger whole. When connected, an interface stub is given a pointer to the server object to which
		/// it should forward method invocations that it receives. Although it is useful to refer conceptually to a stub manager, meaning
		/// whatever pieces of code and state in the server-side RPC infrastructure that service the remoting of a given object, there is no
		/// direct requirement that the code and state take any particular, well-specified form.
		/// </para>
		/// <para>
		/// The first time a client requests a pointer to an interface on a particular object, COM loads an IClassFactory stub in the server
		/// process and uses it to marshal the first pointer back to the client. In the client process, COM loads the generic proxy for the
		/// class factory object and calls its implementation of <c>IMarshal</c> to unmarshal that first pointer. COM then creates the first
		/// interface proxy and hands it a pointer to the RPC channel. Finally, COM returns the <c>IClassFactory</c> pointer to the client,
		/// which uses it to call IClassFactory::CreateInstance, passing it a reference to the interface.
		/// </para>
		/// <para>
		/// Back in the server process, COM now creates a new instance of the object, along with a stub for the requested interface. This
		/// stub marshals the interface pointer back to the client process, where another object proxy is created, this time for the object
		/// itself. Also created is a proxy for the requested interface, a pointer to which is returned to the client. With subsequent calls
		/// to other interfaces on the object, COM will load the appropriate interface stubs and proxies as needed.
		/// </para>
		/// <para>
		/// When a new interface proxy is created, COM hands it a pointer to the proxy manager's implementation of IUnknown, to which it
		/// delegates all QueryInterface calls. Each interface proxy implements two interfaces of its own: the interface it represents and
		/// IRpcProxyBuffer. The interface proxy exposes its own interface directly to clients, which can obtain its pointer by calling
		/// <c>QueryInterface</c> on the proxy manager. Only COM, however, can call <c>IRpcProxyBuffer</c>, which is used to connect and
		/// disconnect the proxy to the RPC channel. A client cannot query an interface proxy to obtain a pointer to the
		/// <c>IRpcProxyBuffer</c> interface.
		/// </para>
		/// <para>
		/// On the server side, each interface stub implements IRpcStubBuffer. The server code acting as a stub manager calls
		/// IRpcStubBuffer::Connect and passes the interface stub the IUnknown pointer of its object.
		/// </para>
		/// <para>
		/// When an interface proxy receives a method invocation, it obtains a marshaling packet from its RPC channel through a call to
		/// IRpcChannelBuffer::GetBuffer. The process of marshaling the arguments will copy data into the buffer. When marshaling is
		/// complete, the interface proxy invokes IRpcChannelBuffer::SendReceive to send the marshaled packet to the corresponding interface
		/// stub. When <c>IRpcChannelBuffer::SendReceive</c> returns, the buffer into which the arguments were marshaled will have been
		/// replaced by a new buffer containing the return values marshaled from the interface stub. The interface proxy unmarshals the
		/// return values, invokes IRpcChannelBuffer::FreeBuffer to free the buffer, and then returns the return values to the original
		/// caller of the method.
		/// </para>
		/// <para>
		/// It is the implementation of IRpcChannelBuffer::SendReceive that actually sends the request to the server process and that knows
		/// how to identify the server process and, within that process, the object to which the request should be sent. The channel
		/// implementation also knows how to forward the request on to the appropriate stub manager in that process. The interface stub
		/// unmarshals the arguments from the provided buffer, invokes the indicated method on the server object, and marshals the return
		/// values back into a new buffer allocated by a call to IRpcChannelBuffer::GetBuffer. The channel then transmits the return data
		/// packet back to the interface proxy, which is still in the middle of <c>IRpcChannelBuffer::SendReceive</c>, which returns to the
		/// interface proxy.
		/// </para>
		/// <para>
		/// A particular instance of an interface proxy can be used to service more than one interface, as long as the following conditions
		/// are met:
		/// </para>
		/// <list type="bullet">
		/// <item>
		/// <term>The IIDs of the affected interfaces must be mapped to the appropriate ProxyStubClsid in the system registry.</term>
		/// </item>
		/// <item>
		/// <term>
		/// The interface proxy must support calls to QueryInterface from one supported interface to the other interfaces, as usual, as well
		/// as from IUnknown and IRpcProxyBuffer.
		/// </term>
		/// </item>
		/// </list>
		/// <para>
		/// A single instance of an interface stub can also service more than one interface, but only if that set of interfaces has a strict
		/// single-inheritance relationship. This restriction exists because the stub can direct method invocations to multiple interfaces
		/// only where it knows in advance which methods are implemented on which interfaces.
		/// </para>
		/// <para>
		/// At various times, proxies and stubs will have need to allocate or free memory. Interface proxies, for example, will need to
		/// allocate memory in which to return out parameters to their caller. In this respect, interface proxies and interface stubs are
		/// just normal COM components, in that they should use the standard task allocator. (See CoGetMalloc.)
		/// </para>
		/// </remarks>
		// https://docs.microsoft.com/en-us/windows/desktop/api/objidl/nn-objidl-imarshal
		[PInvokeData("objidl.h", MSDNShortId = "e6f08949-f27d-4aba-adff-eaf9c356a928")]
		[ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("00000003-0000-0000-C000-000000000046")]
		public interface IMarshal
		{
			/// <summary>Retrieves the CLSID of the unmarshaling code.</summary>
			/// <param name="riid">A reference to the identifier of the interface to be marshaled.</param>
			/// <param name="pv">
			/// A pointer to the interface to be marshaled; can be <c>NULL</c> if the caller does not have a pointer to the desired interface.
			/// </param>
			/// <param name="dwDestContext">
			/// The destination context where the specified interface is to be unmarshaled. Possible values come from the enumeration
			/// MSHCTX. Unmarshaling can occur either in another apartment of the current process (MSHCTX_INPROC) or in another process on
			/// the same computer as the current process (MSHCTX_LOCAL).
			/// </param>
			/// <param name="pvDestContext">This parameter is reserved and must be <c>NULL</c>.</param>
			/// <param name="mshlflags">
			/// Indicates whether the data to be marshaled is to be transmitted back to the client process, the typical caseâ€”or written to
			/// a global table, where it can be retrieved by multiple clients. Possible values come from the MSHLFLAGS enumeration.
			/// </param>
			/// <returns>A pointer that receives the CLSID to be used to create a proxy in the client process.</returns>
			/// <remarks>
			/// <para>
			/// This method is called indirectly, in a call to CoMarshalInterface, by whatever code in the server process is responsible for
			/// marshaling a pointer to an interface on an object. This marshaling code is usually a stub generated by COM for one of
			/// several interfaces that can marshal a pointer to an interface implemented on an entirely different object. Examples include
			/// the IClassFactory and IOleItemContainer interfaces. For purposes of discussion, the code responsible for marshaling a
			/// pointer is called the marshaling stub.
			/// </para>
			/// <para>
			/// To create a proxy for an object, COM requires two pieces of information from the original object: the amount of data to be
			/// written to the marshaling stream and the proxy's CLSID.
			/// </para>
			/// <para>The marshaling stub obtains these two pieces of information with successive calls to CoGetMarshalSizeMax and CoMarshalInterface.</para>
			/// <para>Notes to Callers</para>
			/// <para>
			/// The marshaling stub calls the object's implementation of this method to obtain the CLSID to be used in creating an instance
			/// of the proxy. The client, upon receiving the CLSID, loads the DLL listed for it in the system registry.
			/// </para>
			/// <para>
			/// You do not explicitly call this method if you are implementing existing COM interfaces or using the Microsoft Interface
			/// Definition Language (MIDL) to define your own interfaces. In either case, the stub automatically makes the call. See
			/// Defining COM Interfaces.
			/// </para>
			/// <para>
			/// If you are not using MIDL to define your own interface, your stub must call this method, either directly or indirectly, to
			/// get the CLSID that the client-side COM library needs to create a proxy for the object implementing the interface.
			/// </para>
			/// <para>
			/// If the caller has a pointer to the interface to be marshaled, it should, as a matter of efficiency, use the pv parameter to
			/// pass that pointer. In this way, an implementation that may use such a pointer to determine the appropriate CLSID for the
			/// proxy does not have to call QueryInterface on itself. If a caller does not have a pointer to the interface to be marshaled,
			/// it can pass <c>NULL</c>.
			/// </para>
			/// <para>Notes to Implementers</para>
			/// <para>
			/// COM calls <c>GetUnmarshalClass</c> to obtain the CLSID to be used for creating a proxy in the client process. The CLSID to
			/// be used for a proxy is normally not that of the original object, but one you will have generated (using the Guidgen.exe
			/// tool) specifically for your proxy object.
			/// </para>
			/// <para>
			/// Implement this method for each object that provides marshaling for one or more of its interfaces. The code responsible for
			/// marshaling the object writes the CLSID, along with the marshaling data, to a stream; COM extracts the CLSID and data from
			/// the stream on the receiving side.
			/// </para>
			/// <para>
			/// If your proxy implementation consists simply of copying the entire original object into the client process, thereby
			/// eliminating the need to forward calls to the original object, the CLSID returned would be the same as that of the original
			/// object. This strategy, of course, is advisable only for objects that are not expected to change.
			/// </para>
			/// <para>
			/// If the pv parameter is <c>NULL</c> and your implementation needs an interface pointer, it can call QueryInterface on the
			/// current object to get it. The pv parameter exists merely to improve efficiency.
			/// </para>
			/// <para>
			/// To ensure that your implementation of <c>GetUnmarshalClass</c> continues to work properly as new destination contexts are
			/// supported in the future, delegate marshaling to the COM default implementation for all dwDestContext values that your
			/// implementation does not handle. To delegate marshaling to the COM default implementation, call the CoGetStandardMarshal function.
			/// </para>
			/// <para>
			/// <c>Note</c> The <c>ThreadingModel</c> registry value must be <c>Both</c> for an in-process server that implements the CLSID
			/// returned from the <c>GetUnmarshalClass</c> method. For more information, see InprocServer32.
			/// </para>
			/// </remarks>
			// https://docs.microsoft.com/en-us/windows/desktop/api/objidl/nf-objidl-imarshal-getunmarshalclass HRESULT GetUnmarshalClass(
			// REFIID riid, void *pv, DWORD dwDestContext, void *pvDestContext, DWORD mshlflags, CLSID *pCid );
			Guid GetUnmarshalClass(in Guid riid, [In, Optional, MarshalAs(UnmanagedType.IUnknown)] object pv, [In] MSHCTX dwDestContext,
				[In, Optional] IntPtr pvDestContext, [In] MSHLFLAGS mshlflags);

			/// <summary>Retrieves the maximum size of the buffer that will be needed during marshaling.</summary>
			/// <param name="riid">A reference to the identifier of the interface to be marshaled.</param>
			/// <param name="pv">The interface pointer to be marshaled. This parameter can be <c>NULL</c>.</param>
			/// <param name="dwDestContext">
			/// The destination context where the specified interface is to be unmarshaled. Possible values come from the enumeration
			/// MSHCTX. Unmarshaling can occur either in another apartment of the current process (MSHCTX_INPROC) or in another process on
			/// the same computer as the current process (MSHCTX_LOCAL).
			/// </param>
			/// <param name="pvDestContext">This parameter is reserved and must be <c>NULL</c>.</param>
			/// <param name="mshlflags">
			/// Indicates whether the data to be marshaled is to be transmitted back to the client processâ€”the typical caseâ€”or written
			/// to a global table, where it can be retrieved by multiple clients. Possible values come from the MSHLFLAGS enumeration.
			/// </param>
			/// <returns>A pointer to a variable that receives the maximum size of the buffer.</returns>
			/// <remarks>
			/// <para>
			/// This method is called indirectly, in a call to CoGetMarshalSizeMax, by whatever code in the server process is responsible
			/// for marshaling a pointer to an interface on an object. This marshaling code is usually a stub generated by COM for one of
			/// several interfaces that can marshal a pointer to an interface implemented on an entirely different object. Examples include
			/// the IClassFactory and IOleItemContainer interfaces. For purposes of discussion, the code responsible for marshaling a
			/// pointer is called the marshaling stub.
			/// </para>
			/// <para>
			/// To create a proxy for an object, COM requires two pieces of information from the original object: the amount of data to be
			/// written to the marshaling stream and the proxy's CLSID.
			/// </para>
			/// <para>The marshaling stub obtains these two pieces of information with successive calls to CoGetMarshalSizeMax and CoMarshalInterface.</para>
			/// <para>Notes to Callers</para>
			/// <para>
			/// The marshaling stub, through a call to CoGetMarshalSizeMax, calls the object's implementation of this method to preallocate
			/// the stream buffer that will be passed to MarshalInterface.
			/// </para>
			/// <para>
			/// You do not explicitly call this method if you are implementing existing COM interfaces or using the Microsoft Interface
			/// Definition Language (MIDL) to define your own custom interfaces. In either case, the MIDL-generated stub automatically makes
			/// the call.
			/// </para>
			/// <para>
			/// If you are not using MIDL to define your own interface (see Defining COM Interfaces), your marshaling stub does not have to
			/// call <c>GetMarshalSizeMax</c>, although doing so is highly recommended. An object knows better than an interface stub what
			/// the maximum size of a marshaling data packet is likely to be. Therefore, unless you are providing an automatically growing
			/// stream that is so efficient that the overhead of expanding it is insignificant, you should call this method even when
			/// implementing your own interfaces.
			/// </para>
			/// <para>
			/// The value returned by this method is guaranteed to be valid only as long as the internal state of the object being marshaled
			/// does not change. Therefore, the actual marshaling should be done immediately after this function returns, or the stub runs
			/// the risk that the object, because of some change in state, might require more memory to marshal than it originally indicated.
			/// </para>
			/// <para>Notes to Implementers</para>
			/// <para>
			/// Your implementation of MarshalInterface will use the preallocated buffer to write marshaling data into the stream. If the
			/// buffer is too small, the marshaling operation will fail. Therefore, the value returned by this method must be a conservative
			/// estimate of the amount of data that will be needed to marshal the interface. Violation of this requirement should be treated
			/// as a catastrophic error.
			/// </para>
			/// <para>
			/// In a subsequent call to MarshalInterface, your IMarshal implementation cannot rely on the caller actually having called
			/// <c>GetMarshalSizeMax</c> beforehand. It must still be wary of STG_E_MEDIUMFULL errors returned by the stream and be prepared
			/// to handle them gracefully.
			/// </para>
			/// <para>
			/// To ensure that your implementation of <c>GetMarshalSizeMax</c> will continue to work properly as new destination contexts
			/// are supported in the future, delegate marshaling to the COM default implementation for all dwDestContext values that your
			/// implementation does not understand. To delegate marshaling to the COM default implementation, call the CoGetStandardMarshal function.
			/// </para>
			/// </remarks>
			// https://docs.microsoft.com/en-us/windows/desktop/api/objidl/nf-objidl-imarshal-getmarshalsizemax HRESULT GetMarshalSizeMax(
			// REFIID riid, void *pv, DWORD dwDestContext, void *pvDestContext, DWORD mshlflags, DWORD *pSize );
			uint GetMarshalSizeMax(in Guid riid, [In, Optional, MarshalAs(UnmanagedType.IUnknown)] object pv, [In] MSHCTX dwDestContext,
				[In, Optional] IntPtr pvDestContext, [In] MSHLFLAGS mshlflags);

			/// <summary>Marshals an interface pointer.</summary>
			/// <param name="pStm">A pointer to the stream to be used during marshaling.</param>
			/// <param name="riid">
			/// A reference to the identifier of the interface to be marshaled. This interface must be derived from the IUnknown interface.
			/// </param>
			/// <param name="pv">
			/// A pointer to the interface pointer to be marshaled. This parameter can be <c>NULL</c> if the caller does not have a pointer
			/// to the desired interface.
			/// </param>
			/// <param name="dwDestContext">
			/// The destination context where the specified interface is to be unmarshaled. Possible values for dwDestContext come from the
			/// enumeration MSHCTX. Currently, unmarshaling can occur either in another apartment of the current process (MSHCTX_INPROC) or
			/// in another process on the same computer as the current process (MSHCTX_LOCAL).
			/// </param>
			/// <param name="pvDestContext">This parameter is reserved and must be 0.</param>
			/// <param name="mshlflags">
			/// Indicates whether the data to be marshaled is to be transmitted back to the client process—the typical case—or written to a
			/// global table, where it can be retrieved by multiple clients. Possible values come from the MSHLFLAGS enumeration.
			/// </param>
			/// <remarks>
			/// <para>
			/// This method is called indirectly, in a call to CoMarshalInterface, by whatever code in the server process is responsible for
			/// marshaling a pointer to an interface on an object. This marshaling code is usually a stub generated by COM for one of
			/// several interfaces that can marshal a pointer to an interface implemented on an entirely different object. Examples include
			/// the IClassFactory and IOleItemContainer interfaces. For purposes of discussion, the code responsible for marshaling a
			/// pointer is called the marshaling stub.
			/// </para>
			/// <para>Notes to Callers</para>
			/// <para>
			/// Typically, rather than calling <c>MarshalInterface</c> directly, your marshaling stub instead should call the
			/// CoMarshalInterface function, which contains a call to this method. The stub makes this call to command an object to write
			/// its marshaling data into a stream. The stub then either passes the marshaling data back to the client process or writes it
			/// to a global table, where it can be unmarshaled by multiple clients. The stub's call to <c>CoMarshalInterface</c> is normally
			/// preceded by a call to CoGetMarshalSizeMax to get the maximum size of the stream buffer into which the marshaling data will
			/// be written.
			/// </para>
			/// <para>
			/// You do not explicitly call this method if you are implementing existing COM interfaces or defining your own interfaces using
			/// the Microsoft Interface Definition Language (MIDL). In either case, the MIDL-generated stub automatically makes the call.
			/// </para>
			/// <para>
			/// If you are not using MIDL to define your own interface, your marshaling stub must call this method, either directly or
			/// indirectly. Your stub implementation should call <c>MarshalInterface</c> immediately after its previous call to
			/// IMarshal::GetMarshalSizeMax returns. Because the value returned by <c>GetMarshalSizeMax</c> is guaranteed to be valid only
			/// as long as the internal state of the object being marshaled does not change, a delay in calling <c>MarshalInterface</c> runs
			/// the risk that the object will require a larger stream buffer than originally indicated.
			/// </para>
			/// <para>
			/// If the caller has a pointer to the interface to be marshaled, it should, as a matter of efficiency, use the pv parameter to
			/// pass that pointer. In this way, an implementation that may use such a pointer to determine the appropriate CLSID for the
			/// proxy does not have to call QueryInterface on itself. If a caller does not have a pointer to the interface to be marshaled,
			/// it can pass <c>NULL</c>.
			/// </para>
			/// <para>Notes to Implementers</para>
			/// <para>
			/// Your implementation of <c>MarshalInterface</c> must write to the stream whatever data is needed to initialize the proxy on
			/// the receiving side. Such data would include a reference to the interface to be marshaled, a MSHLFLAGS value specifying
			/// whether the data should be returned to the client process or written to a global table, and whatever is needed to connect to
			/// the object, such as a named pipe, handle to a window, or pointer to an RPC channel.
			/// </para>
			/// <para>
			/// Your implementation should not assume that the stream is large enough to hold all the data. Rather, it should gracefully
			/// handle a STG_E_MEDIUMFULL error. Just before exiting, your implementation should position the seek pointer in the stream
			/// immediately after the last byte of data written.
			/// </para>
			/// <para>
			/// If the pv parameter is <c>NULL</c> and your implementation needs an interface pointer, it can call QueryInterface on the
			/// current object to get it. The pv parameter exists merely to improve efficiency.
			/// </para>
			/// <para>
			/// To ensure that your implementation of <c>MarshalInterface</c> continues to work properly as new destination contexts are
			/// supported in the future, delegate marshaling to the COM default implementation for all dwDestContext values that your
			/// implementation does not handle. To delegate marshaling to the COM default implementation, call the CoGetStandardMarshal
			/// helper function.
			/// </para>
			/// <para>
			/// Using the MSHLFLAGS enumeration, callers can specify whether an interface pointer is to be marshaled back to a single client
			/// or written to a global table, where it can be unmarshaled by multiple clients. You must make sure that your object can
			/// handle calls from the multiple proxies that might be created from the same initialization data.
			/// </para>
			/// </remarks>
			// https://docs.microsoft.com/en-us/windows/desktop/api/objidl/nf-objidl-imarshal-marshalinterface HRESULT MarshalInterface(
			// IStream *pStm, REFIID riid, void *pv, DWORD dwDestContext, void *pvDestContext, DWORD mshlflags );
			void MarshalInterface([In] IStream pStm, in Guid riid, [In, Optional, MarshalAs(UnmanagedType.IUnknown)] object pv,
				[In] MSHCTX dwDestContext, [In, Optional] IntPtr pvDestContext, [In] MSHLFLAGS mshlflags);

			/// <summary>Unmarshals an interface pointer.</summary>
			/// <param name="pStm">A pointer to the stream from which the interface pointer is to be unmarshaled.</param>
			/// <param name="riid">A reference to the identifier of the interface to be unmarshaled.</param>
			/// <returns>
			/// The address of pointer variable that receives the interface pointer. Upon successful return, *ppv contains the requested
			/// interface pointer of the interface to be unmarshaled.
			/// </returns>
			/// <remarks>
			/// <para>The COM library in the process where unmarshaling is to occur calls the proxy's implementation of this method.</para>
			/// <para>Notes to Callers</para>
			/// <para>
			/// You do not call this method directly. There are, however, some situations in which you might call it indirectly through a
			/// call to CoUnmarshalInterface. For example, if you are implementing a stub, your implementation would call
			/// <c>CoUnmarshalInterface</c> when the stub receives an interface pointer as a parameter in a method call.
			/// </para>
			/// <para>Notes to Implementers</para>
			/// <para>
			/// The proxy's implementation should read the data written to the stream by the original object's implementation of
			/// IMarshal::MarshalInterface and use that data to initialize the proxy object whose CLSID was returned by the marshaling
			/// stub's call to the original object's implementation of IMarshal::GetUnmarshalClass.
			/// </para>
			/// <para>
			/// To return the appropriate interface pointer, the proxy implementation can simply call QueryInterface on itself, passing the
			/// riid and ppv parameters. However, your implementation of <c>UnmarshalInterface</c> is free to create a different object and,
			/// if necessary, return a pointer to it.
			/// </para>
			/// <para>
			/// Just before exiting, even if exiting with an error, your implementation should reposition the seek pointer in the stream
			/// immediately after the last byte of data read.
			/// </para>
			/// </remarks>
			// https://docs.microsoft.com/en-us/windows/desktop/api/objidl/nf-objidl-imarshal-unmarshalinterface HRESULT UnmarshalInterface(
			// IStream *pStm, REFIID riid, void **ppv );
			[return: MarshalAs(UnmanagedType.IUnknown)]
			object UnmarshalInterface([In] IStream pStm, in Guid riid);

			/// <summary>Destroys a marshaled data packet.</summary>
			/// <param name="pStm">A pointer to a stream that contains the data packet to be destroyed.</param>
			/// <remarks>
			/// <para>
			/// If an object's marshaled data packet does not get unmarshaled in the client process space and the packet is no longer
			/// needed, the client calls <c>ReleaseMarshalData</c> on the proxy's IMarshal implementation to instruct the object to destroy
			/// the data packet. The call occurs within the CoReleaseMarshalData function. The data packet serves as an additional reference
			/// on the object, and releasing the data is like releasing an interface pointer by calling Release.
			/// </para>
			/// <para>
			/// If the marshaled data packet somehow does not arrive in the client process or if <c>ReleaseMarshalData</c> is not
			/// successfully re-created in the proxy, COM can call this method on the object itself.
			/// </para>
			/// <para>Notes to Callers</para>
			/// <para>
			/// You will rarely if ever have occasion to call this method yourself. A possible exception would be if you were to implement
			/// IMarshal on a class factory for a class object on which you are also implementing <c>IMarshal</c>. In this case, if you were
			/// marshaling the object to a table where it could be retrieved by multiple clients, you might, as part of your unmarshaling
			/// routine, call <c>ReleaseMarshalData</c> to release the data packet for each proxy.
			/// </para>
			/// <para>Notes to Implementers</para>
			/// <para>
			/// If your implementation stores state information about marshaled data packets, you can use this method to release the state
			/// information associated with the data packet represented by pStm. Your implementation should also position the seek pointer
			/// in the stream past the last byte of data.
			/// </para>
			/// </remarks>
			// https://docs.microsoft.com/en-us/windows/desktop/api/objidl/nf-objidl-imarshal-releasemarshaldata HRESULT ReleaseMarshalData(
			// IStream *pStm );
			void ReleaseMarshalData([In] IStream pStm);

			/// <summary>
			/// Releases all connections to an object. The object's server calls the object's implementation of this method prior to
			/// shutting down.
			/// </summary>
			/// <param name="dwReserved">This parameter is reserved and must be 0.</param>
			/// <remarks>
			/// <para>This method is implemented on the object, not the proxy.</para>
			/// <para>Notes to Callers</para>
			/// <para>
			/// The usual case in which this method is called occurs when an end user forcibly closes a COM server that has one or more
			/// running objects that implement IMarshal. Prior to shutting down, the server calls the CoDisconnectObject function to release
			/// external connections to all its running objects. For each object that implements <c>IMarshal</c>, however, this function
			/// calls <c>DisconnectObject</c> so that each object that manages its own marshaling can take steps to notify its proxy that it
			/// is about to shut down.
			/// </para>
			/// <para>Notes to Implementers</para>
			/// <para>
			/// As part of its normal shutdown code, a server should call CoDisconnectObject, which in turn calls <c>DisconnectObject</c>,
			/// on each of its running objects that implements IMarshal.
			/// </para>
			/// <para>
			/// The outcome of any implementation of this method should be to enable a proxy to respond to all subsequent calls from its
			/// client by returning RPC_E_DISCONNECTED or CO_E_OBJNOTCONNECTED rather than attempting to forward the calls on to the
			/// original object. It is up to the client to destroy the proxy.
			/// </para>
			/// <para>
			/// If you are implementing this method for an immutable object, such as a moniker, your implementation does not need to do
			/// anything because such objects are typically copied whole into the client's address space. Therefore, they have neither a
			/// proxy nor a connection to the original object. For more information on marshaling immutable objects, see the "When to
			/// Implement" section of the IMarshal topic.
			/// </para>
			/// </remarks>
			// https://docs.microsoft.com/en-us/windows/desktop/api/objidl/nf-objidl-imarshal-disconnectobject HRESULT DisconnectObject(
			// DWORD dwReserved );
			void DisconnectObject([In, Optional] uint dwReserved);
		}

		/// <summary>Provides additional information about the marshaling context to custom-marshaled objects and unmarshalers.</summary>
		/// <remarks>
		/// Implement <c>IMarshalingStream</c> interface if you have IStream implementations that call the marshaling APIs and provide the
		/// correct value of any of the attributes. This is essential only for <c>IStream</c> implementations that are used in hybrid policy processes.
		/// </remarks>
		// https://docs.microsoft.com/en-us/windows/win32/api/objidl/nn-objidl-imarshalingstream
		[PInvokeData("objidl.h", MSDNShortId = "NN:objidl.IMarshalingStream")]
		[ComImport, Guid("D8F2F5E6-6102-4863-9F26-389A4676EFDE"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
		public interface IMarshalingStream : IStreamV
		{
			/// <summary>
			/// The <c>Read</c> method reads a specified number of bytes from the stream object into memory, starting at the current seek pointer.
			/// </summary>
			/// <param name="pv">A pointer to the buffer which the stream data is read into.</param>
			/// <param name="cb">The number of bytes of data to read from the stream object.</param>
			/// <param name="pcbRead">
			/// <para>A pointer to a <c>ULONG</c> variable that receives the actual number of bytes read from the stream object.</para>
			/// <para><c>Note</c> The number of bytes read may be zero.</para>
			/// </param>
			/// <remarks>
			/// <para>
			/// This method reads bytes from this stream object into memory. The stream object must be opened in <c>STGM_READ</c> mode. This
			/// method adjusts the seek pointer by the actual number of bytes read.
			/// </para>
			/// <para>The number of bytes actually read is also returned in the pcbRead parameter.</para>
			/// <para>Notes to Callers</para>
			/// <para>
			/// The actual number of bytes read can be less than the number of bytes requested if an error occurs or if the end of the
			/// stream is reached during the read operation. The number of bytes returned should always be compared to the number of bytes
			/// requested. If the number of bytes returned is less than the number of bytes requested, it usually means the <c>Read</c>
			/// method attempted to read past the end of the stream.
			/// </para>
			/// <para>The application should handle both a returned error and <c>S_OK</c> return values on end-of-stream read operations.</para>
			/// </remarks>
			// https://docs.microsoft.com/en-us/windows/desktop/api/objidl/nf-objidl-isequentialstream-read HRESULT Read( void *pv, ULONG
			// cb, ULONG *pcbRead );
			[PInvokeData("objidl.h", MSDNShortId = "934a90bb-5ed0-4d80-9906-352ad8586655")]
			[PreserveSig]
			new HRESULT Read(byte[] pv, uint cb, out uint pcbRead);

			/// <summary>
			/// The <c>Write</c> method writes a specified number of bytes into the stream object starting at the current seek pointer.
			/// </summary>
			/// <param name="pv">
			/// A pointer to the buffer that contains the data that is to be written to the stream. A valid pointer must be provided for
			/// this parameter even when cb is zero.
			/// </param>
			/// <param name="cb">The number of bytes of data to attempt to write into the stream. This value can be zero.</param>
			/// <param name="pcbWritten">
			/// A pointer to a <c>ULONG</c> variable where this method writes the actual number of bytes written to the stream object. The
			/// caller can set this pointer to <c>NULL</c>, in which case this method does not provide the actual number of bytes written.
			/// </param>
			/// <remarks>
			/// <para>
			/// <c>ISequentialStream::Write</c> writes the specified data to a stream object. The seek pointer is adjusted for the number of
			/// bytes actually written. The number of bytes actually written is returned in the pcbWritten parameter. If the byte count is
			/// zero bytes, the write operation has no effect.
			/// </para>
			/// <para>
			/// If the seek pointer is currently past the end of the stream and the byte count is nonzero, this method increases the size of
			/// the stream to the seek pointer and writes the specified bytes starting at the seek pointer. The fill bytes written to the
			/// stream are not initialized to any particular value. This is the same as the end-of-file behavior in the MS-DOS FAT file system.
			/// </para>
			/// <para>
			/// With a zero byte count and a seek pointer past the end of the stream, this method does not create the fill bytes to increase
			/// the stream to the seek pointer. In this case, you must call the IStream::SetSize method to increase the size of the stream
			/// and write the fill bytes.
			/// </para>
			/// <para>The pcbWritten parameter can have a value even if an error occurs.</para>
			/// <para>
			/// In the COM-provided implementation, stream objects are not sparse. Any fill bytes are eventually allocated on the disk and
			/// assigned to the stream.
			/// </para>
			/// </remarks>
			// https://docs.microsoft.com/en-us/windows/desktop/api/objidl/nf-objidl-isequentialstream-write HRESULT Write( const void *pv,
			// ULONG cb, ULONG *pcbWritten );
			[PInvokeData("objidl.h", MSDNShortId = "f0323dda-6c31-4411-bf20-9650162109c0")]
			[PreserveSig]
			new HRESULT Write(byte[] pv, uint cb, out uint pcbWritten);

			/// <summary>
			/// The <c>Seek</c> method changes the seek pointer to a new location. The new location is relative to either the beginning of
			/// the stream, the end of the stream, or the current seek pointer.
			/// </summary>
			/// <param name="dlibMove">
			/// The displacement to be added to the location indicated by the dwOrigin parameter. If dwOrigin is <c>STREAM_SEEK_SET</c>,
			/// this is interpreted as an unsigned value rather than a signed value.
			/// </param>
			/// <param name="dwOrigin">
			/// The origin for the displacement specified in dlibMove. The origin can be the beginning of the file (
			/// <c>STREAM_SEEK_SET</c>), the current seek pointer ( <c>STREAM_SEEK_CUR</c>), or the end of the file (
			/// <c>STREAM_SEEK_END</c>). For more information about values, see the STREAM_SEEK enumeration.
			/// </param>
			/// <param name="plibNewPosition">
			/// <para>A pointer to the location where this method writes the value of the new seek pointer from the beginning of the stream.</para>
			/// <para>You can set this pointer to <c>NULL</c>. In this case, this method does not provide the new seek pointer.</para>
			/// </param>
			/// <returns>This method can return one of these values.</returns>
			/// <remarks>
			/// <para>
			/// <c>IStream::Seek</c> changes the seek pointer so that subsequent read and write operations can be performed at a different
			/// location in the stream object. It is an error to seek before the beginning of the stream. It is not, however, an error to
			/// seek past the end of the stream. Seeking past the end of the stream is useful for subsequent write operations, as the stream
			/// byte range will be extended to the new seek position immediately before the write is complete.
			/// </para>
			/// <para>
			/// You can also use this method to obtain the current value of the seek pointer by calling this method with the dwOrigin
			/// parameter set to <c>STREAM_SEEK_CUR</c> and the dlibMove parameter set to 0 so that the seek pointer is not changed. The
			/// current seek pointer is returned in the plibNewPosition parameter.
			/// </para>
			/// </remarks>
			// https://docs.microsoft.com/en-us/windows/win32/api/objidl/nf-objidl-istream-seek HRESULT Seek( LARGE_INTEGER dlibMove, DWORD
			// dwOrigin, ULARGE_INTEGER *plibNewPosition );
			[PreserveSig]
			new HRESULT Seek(long dlibMove, STREAM_SEEK dwOrigin, IntPtr plibNewPosition);

			/// <summary>The <c>SetSize</c> method changes the size of the stream object.</summary>
			/// <param name="libNewSize">Specifies the new size, in bytes, of the stream.</param>
			/// <returns>This method can return one of these values.</returns>
			/// <remarks>
			/// <para>
			/// <c>IStream::SetSize</c> changes the size of the stream object. Call this method to preallocate space for the stream. If the
			/// libNewSize parameter is larger than the current stream size, the stream is extended to the indicated size by filling the
			/// intervening space with bytes of undefined value. This operation is similar to the ISequentialStream::Write method if the
			/// seek pointer is past the current end of the stream.
			/// </para>
			/// <para>If the libNewSize parameter is smaller than the current stream, the stream is truncated to the indicated size.</para>
			/// <para>The seek pointer is not affected by the change in stream size.</para>
			/// <para>Calling <c>IStream::SetSize</c> can be an effective way to obtain a large chunk of contiguous space.</para>
			/// </remarks>
			// https://docs.microsoft.com/en-us/windows/win32/api/objidl/nf-objidl-istream-setsize HRESULT SetSize( ULARGE_INTEGER
			// libNewSize );
			[PreserveSig]
			new HRESULT SetSize(long libNewSize);

			/// <summary>
			/// The <c>CopyTo</c> method copies a specified number of bytes from the current seek pointer in the stream to the current seek
			/// pointer in another stream.
			/// </summary>
			/// <param name="pstm">
			/// A pointer to the destination stream. The stream pointed to by pstm can be a new stream or a clone of the source stream.
			/// </param>
			/// <param name="cb">The number of bytes to copy from the source stream.</param>
			/// <param name="pcbRead">
			/// A pointer to the location where this method writes the actual number of bytes read from the source. You can set this pointer
			/// to <c>NULL</c>. In this case, this method does not provide the actual number of bytes read.
			/// </param>
			/// <param name="pcbWritten">
			/// A pointer to the location where this method writes the actual number of bytes written to the destination. You can set this
			/// pointer to <c>NULL</c>. In this case, this method does not provide the actual number of bytes written.
			/// </param>
			/// <returns>This method can return one of these values.</returns>
			/// <remarks>
			/// <para>
			/// The <c>CopyTo</c> method copies the specified bytes from one stream to another. It can also be used to copy a stream to
			/// itself. The seek pointer in each stream instance is adjusted for the number of bytes read or written. This method is
			/// equivalent to reading cb bytes into memory using ISequentialStream::Read and then immediately writing them to the
			/// destination stream using ISequentialStream::Write, although <c>IStream::CopyTo</c> will be more efficient.
			/// </para>
			/// <para>The destination stream can be a clone of the source stream created by calling the IStream::Clone method.</para>
			/// <para>
			/// If <c>IStream::CopyTo</c> returns an error, you cannot assume that the seek pointers are valid for either the source or
			/// destination. Additionally, the values of pcbRead and pcbWritten are not meaningful even though they are returned.
			/// </para>
			/// <para>If <c>IStream::CopyTo</c> returns successfully, the actual number of bytes read and written are the same.</para>
			/// <para>
			/// To copy the remainder of the source from the current seek pointer, specify the maximum large integer value for the cb
			/// parameter. If the seek pointer is the beginning of the stream, this operation copies the entire stream.
			/// </para>
			/// </remarks>
			// https://docs.microsoft.com/en-us/windows/win32/api/objidl/nf-objidl-istream-copyto HRESULT CopyTo( IStream *pstm,
			// ULARGE_INTEGER cb, ULARGE_INTEGER *pcbRead, ULARGE_INTEGER *pcbWritten );
			[PreserveSig]
			new HRESULT CopyTo(IStream pstm, long cb, IntPtr pcbRead, IntPtr pcbWritten);

			/// <summary>
			/// The <c>Commit</c> method ensures that any changes made to a stream object open in transacted mode are reflected in the
			/// parent storage. If the stream object is open in direct mode, <c>IStream::Commit</c> has no effect other than flushing all
			/// memory buffers to the next-level storage object. The COM compound file implementation of streams does not support opening
			/// streams in transacted mode.
			/// </summary>
			/// <param name="grfCommitFlags">
			/// Controls how the changes for the stream object are committed. See the STGC enumeration for a definition of these values.
			/// </param>
			/// <returns>This method can return one of these values.</returns>
			/// <remarks>
			/// <para>
			/// The <c>Commit</c> method ensures that changes to a stream object opened in transacted mode are reflected in the parent
			/// storage. Changes that have been made to the stream since it was opened or last committed are reflected to the parent storage
			/// object. If the parent is opened in transacted mode, the parent may revert at a later time, rolling back the changes to this
			/// stream object. The compound file implementation does not support the opening of streams in transacted mode, so this method
			/// has very little effect other than to flush memory buffers. For more information, see IStream - Compound File Implementation.
			/// </para>
			/// <para>
			/// If the stream is open in direct mode, this method ensures that any memory buffers have been flushed out to the underlying
			/// storage object. This is much like a flush in traditional file systems.
			/// </para>
			/// <para>
			/// The <c>IStream::Commit</c> method is useful on a direct mode stream when the implementation of the IStream interface is a
			/// wrapper for underlying file system APIs. In this case, <c>IStream::Commit</c> would be connected to the file system's flush call.
			/// </para>
			/// </remarks>
			// https://docs.microsoft.com/en-us/windows/win32/api/objidl/nf-objidl-istream-commit HRESULT Commit( DWORD grfCommitFlags );
			[PreserveSig]
			new HRESULT Commit(STGC grfCommitFlags);

			/// <summary>
			/// The <c>Revert</c> method discards all changes that have been made to a transacted stream since the last IStream::Commit
			/// call. On streams open in direct mode and streams using the COM compound file implementation of <c>IStream::Revert</c>, this
			/// method has no effect.
			/// </summary>
			/// <returns>This method can return one of these values.</returns>
			/// <remarks>The <c>Revert</c> method discards changes made to a transacted stream since the last commit operation.</remarks>
			// https://docs.microsoft.com/en-us/windows/win32/api/objidl/nf-objidl-istream-revert HRESULT Revert();
			[PreserveSig]
			new HRESULT Revert();

			/// <summary>
			/// The <c>LockRegion</c> method restricts access to a specified range of bytes in the stream. Supporting this functionality is
			/// optional since some file systems do not provide it.
			/// </summary>
			/// <param name="libOffset">Integer that specifies the byte offset for the beginning of the range.</param>
			/// <param name="cb">Integer that specifies the length of the range, in bytes, to be restricted.</param>
			/// <param name="dwLockType">Specifies the restrictions being requested on accessing the range.</param>
			/// <returns>This method can return one of these values.</returns>
			/// <remarks>
			/// <para>
			/// The byte range of the stream can be extended. Locking an extended range for the stream is useful as a method of
			/// communication between different instances of the stream without changing data that is actually part of the stream.
			/// </para>
			/// <para>
			/// Three types of locking can be supported: locking to exclude other writers, locking to exclude other readers or writers, and
			/// locking that allows only one requester to obtain a lock on the given range, which is usually an alias for one of the other
			/// two lock types. A given stream instance might support either of the first two types, or both. The lock type is specified by
			/// dwLockType, using a value from the LOCKTYPE enumeration.
			/// </para>
			/// <para>
			/// Any region locked with <c>IStream::LockRegion</c> must later be explicitly unlocked by calling IStream::UnlockRegion with
			/// exactly the same values for the libOffset, cb, and dwLockType parameters. The region must be unlocked before the stream is
			/// released. Two adjacent regions cannot be locked separately and then unlocked with a single unlock call.
			/// </para>
			/// <para>Notes to Callers</para>
			/// <para>
			/// Since the type of locking supported is optional and can vary in different implementations of IStream, you must provide code
			/// to deal with the STG_E_INVALIDFUNCTION error.
			/// </para>
			/// <para>
			/// The <c>LockRegion</c> method has no effect in the compound file implementation, because the implementation does not support
			/// range locking.
			/// </para>
			/// <para>Notes to Implementers</para>
			/// <para>
			/// Support for this method is optional for implementations of stream objects since it may not be supported by the underlying
			/// file system. The type of locking supported is also optional. The STG_E_INVALIDFUNCTION error is returned if the requested
			/// type of locking is not supported.
			/// </para>
			/// </remarks>
			// https://docs.microsoft.com/en-us/windows/win32/api/objidl/nf-objidl-istream-lockregion HRESULT LockRegion( ULARGE_INTEGER
			// libOffset, ULARGE_INTEGER cb, DWORD dwLockType );
			[PreserveSig]
			new HRESULT LockRegion(long libOffset, long cb, LOCKTYPE dwLockType);

			/// <summary>
			/// The <c>UnlockRegion</c> method removes the access restriction on a range of bytes previously restricted with IStream::LockRegion.
			/// </summary>
			/// <param name="libOffset">Specifies the byte offset for the beginning of the range.</param>
			/// <param name="cb">Specifies, in bytes, the length of the range to be restricted.</param>
			/// <param name="dwLockType">Specifies the access restrictions previously placed on the range.</param>
			/// <returns>This method can return one of these values.</returns>
			/// <remarks>
			/// <c>IStream::UnlockRegion</c> unlocks a region previously locked with the IStream::LockRegion method. Locked regions must
			/// later be explicitly unlocked by calling <c>IStream::UnlockRegion</c> with exactly the same values for the libOffset, cb, and
			/// dwLockType parameters. The region must be unlocked before the stream is released. Two adjacent regions cannot be locked
			/// separately and then unlocked with a single unlock call.
			/// </remarks>
			// https://docs.microsoft.com/en-us/windows/win32/api/objidl/nf-objidl-istream-unlockregion HRESULT UnlockRegion( ULARGE_INTEGER
			// libOffset, ULARGE_INTEGER cb, DWORD dwLockType );
			[PreserveSig]
			new HRESULT UnlockRegion(long libOffset, long cb, LOCKTYPE dwLockType);

			/// <summary>The <c>Stat</c> method retrieves the STATSTG structure for this stream.</summary>
			/// <param name="pstatstg">Pointer to a STATSTG structure where this method places information about this stream object.</param>
			/// <param name="grfStatFlag">
			/// Specifies that this method does not return some of the members in the STATSTG structure, thus saving a memory allocation
			/// operation. Values are taken from the STATFLAG enumeration.
			/// </param>
			/// <returns>This method can return one of these values.</returns>
			/// <remarks>
			/// <c>IStream::Stat</c> retrieves a pointer to the STATSTG structure that contains information about this open stream. When
			/// this stream is within a structured storage and IStorage::EnumElements is called, it creates an enumerator object with the
			/// IEnumSTATSTG interface on it, which can be called to enumerate the storages and streams through the <c>STATSTG</c>
			/// structures associated with each of them.
			/// </remarks>
			// https://docs.microsoft.com/en-us/windows/win32/api/objidl/nf-objidl-istream-stat HRESULT Stat( STATSTG *pstatstg, DWORD
			// grfStatFlag );
			[PreserveSig]
			new HRESULT Stat(out STATSTG pstatstg, STATFLAG grfStatFlag);

			/// <summary>
			/// The <c>Clone</c> method creates a new stream object with its own seek pointer that references the same bytes as the original stream.
			/// </summary>
			/// <param name="ppstm">
			/// When successful, pointer to the location of an IStream pointer to the new stream object. If an error occurs, this parameter
			/// is <c>NULL</c>.
			/// </param>
			/// <returns>This method can return one of these values.</returns>
			/// <remarks>
			/// <para>
			/// The <c>Clone</c> method creates a new stream object for accessing the same bytes but using a separate seek pointer. The new
			/// stream object sees the same data as the source-stream object. Changes written to one object are immediately visible in the
			/// other. Range locking is shared between the stream objects.
			/// </para>
			/// <para>
			/// The initial setting of the seek pointer in the cloned stream instance is the same as the current setting of the seek pointer
			/// in the original stream at the time of the clone operation.
			/// </para>
			/// </remarks>
			// https://docs.microsoft.com/en-us/windows/win32/api/objidl/nf-objidl-istream-clone HRESULT Clone( IStream **ppstm );
			[PreserveSig]
			new HRESULT Clone(out IStream ppstm);

			/// <summary>Gets information about the marshaling context.</summary>
			/// <param name="attribute">The attribute to query.</param>
			/// <param name="pAttributeValue">The value of attribute.</param>
			/// <returns>If this method succeeds, it returns <c>S_OK</c>. Otherwise, it returns an <c>HRESULT</c> error code.</returns>
			/// <remarks>
			/// <para>Each possible value of the attribute parameter is paired with the data type of the attribute this identifies.</para>
			/// <para>You can query the following attributes with this method.</para>
			/// <list type="table">
			/// <listheader>
			/// <term>Attribute</term>
			/// <term>Values</term>
			/// </listheader>
			/// <item>
			/// <term>CO_MARSHALING_SOURCE_IS_APP_CONTAINER</term>
			/// <term>
			/// This attribute is a boolean value, with 0 representing TRUE and nonzero representing FALSE. You can safely cast the value of
			/// the result to BOOL, but it isn't safe for the caller to cast a BOOL* to ULONG_PTR* for the pAttributeValue parameter, or for
			/// the implementation to cast pAttributeValue to BOOL* when setting it.
			/// </term>
			/// </item>
			/// </list>
			/// </remarks>
			// https://docs.microsoft.com/en-us/windows/win32/api/objidl/nf-objidl-imarshalingstream-getmarshalingcontextattribute HRESULT
			// GetMarshalingContextAttribute( CO_MARSHALING_CONTEXT_ATTRIBUTES attribute, ULONG_PTR *pAttributeValue );
			[PreserveSig]
			HRESULT GetMarshalingContextAttribute(CO_MARSHALING_CONTEXT_ATTRIBUTES attribute, out IntPtr pAttributeValue);
		}

		/// <summary>
		/// Enables a client to query an object proxy, or handler, for multiple interfaces by using a single RPC call. By using this
		/// interface, instead of relying on separate calls to IUnknown::QueryInterface, clients can reduce the number of RPC calls that
		/// have to cross thread, process, or machine boundaries and, therefore, the amount of time required to obtain the requested
		/// interface pointers.
		/// </summary>
		// https://docs.microsoft.com/en-us/windows/win32/api/objidl/nn-objidl-imultiqi
		[PInvokeData("objidl.h", MSDNShortId = "NN:objidl.IMultiQI")]
		[ComImport, Guid("00000020-0000-0000-C000-000000000046"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
		public interface IMultiQI
		{
			/// <summary>
			/// <para>Retrieves pointers to multiple supported interfaces on an object.</para>
			/// <para>
			/// Calling this method is equivalent to issuing a series of separate QueryInterface calls except that you do not incur the
			/// overhead of a corresponding number of RPC calls. In multithreaded applications and distributed environments, keeping RPC
			/// calls to a minimum is essential for optimal performance.
			/// </para>
			/// </summary>
			/// <param name="cMQIs">The number of elements in the pMQIs array.</param>
			/// <param name="pMQIs">An array of MULTI_QI structures. For more information, see Remarks.</param>
			/// <returns>
			/// <para>This method can return the following values.</para>
			/// <list type="table">
			/// <listheader>
			/// <term>Return code</term>
			/// <term>Description</term>
			/// </listheader>
			/// <item>
			/// <term>S_OK</term>
			/// <term>The method retrieved pointers to all requested interfaces.</term>
			/// </item>
			/// <item>
			/// <term>S_FALSE</term>
			/// <term>The method retrieved pointers to some, but not all, of the requested interfaces.</term>
			/// </item>
			/// <item>
			/// <term>E_NOINTERFACE</term>
			/// <term>The method retrieved pointers to none of the requested interfaces.</term>
			/// </item>
			/// </list>
			/// </returns>
			/// <remarks>
			/// <para>
			/// The <c>QueryMultipleInterfaces</c> method takes as input an array of MULTI_QI structures. Each structure specifies an
			/// interface IID and contains two additional members for receiving an interface pointer and return value.
			/// </para>
			/// <para>
			/// This method obtains as many requested interface pointers as possible directly from the object proxy. For each interface not
			/// implemented on the proxy, the method calls the server to obtain a pointer. Upon receiving an interface pointer from the
			/// server, the method builds a corresponding interface proxy and returns its pointer along with pointers to the interfaces it
			/// already implements.
			/// </para>
			/// <para>Notes to Callers</para>
			/// <para>
			/// A caller should begin by querying the object proxy for the IMultiQI interface. If the object proxy returns a pointer to this
			/// interface, the caller should then create a MULTI_QI structure for each interface it wants to obtain. Each structure should
			/// specify an interface IID and set its <c>pItf</c> member to <c>NULL</c>. Failure to set the <c>pItf</c> member to <c>NULL</c>
			/// will cause the object proxy to ignore the structure.
			/// </para>
			/// <para>
			/// On return, <c>QueryMultipleInterfaces</c> writes the requested interface pointer and a return value into each MULTI_QI
			/// structure in the client's array. The <c>pItf</c> member receives the pointer; the <c>hr</c> member receives the return value.
			/// </para>
			/// <para>
			/// If the value returned from a call to <c>QueryMultipleInterfaces</c> is S_OK, then pointers were returned for all requested interfaces.
			/// </para>
			/// <para>
			/// If the return value is E_NOINTERFACE, then pointers were returned for none of the requested interfaces. If the return value
			/// is S_FALSE, then pointers to one or more requested interfaces were not returned. In this event, the client should check the
			/// <c>hr</c> member of each MULTI_QI structure to determine which interfaces were acquired and which were not.
			/// </para>
			/// <para>
			/// If a client knows ahead of time that it will be using several of an object's interfaces, it can call
			/// <c>QueryMultipleInterfaces</c> up front and then, later, if a QueryInterface is done for one of the interfaces already
			/// acquired through <c>QueryMultipleInterfaces</c>, no RPC call will be necessary.
			/// </para>
			/// <para>
			/// On return, the caller should check the <c>hr</c> member of each MULTI_QI structure to determine which interface pointers
			/// were and were not returned.
			/// </para>
			/// <para>The client is responsible for releasing each of the acquired interfaces by calling Release.</para>
			/// </remarks>
			// https://docs.microsoft.com/en-us/windows/win32/api/objidlbase/nf-objidlbase-imultiqi-querymultipleinterfaces HRESULT
			// QueryMultipleInterfaces( ULONG cMQIs, MULTI_QI *pMQIs );
			[PreserveSig]
			HRESULT QueryMultipleInterfaces([In] uint cMQIs, [In, Out, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 0)] MULTI_QI[] pMQIs);
		}

		/// <summary>Marks an object that doesn't support being marshaled or stored in the Global Interface Table.</summary>
		// https://docs.microsoft.com/en-us/windows/desktop/api/objidl/nn-objidl-inomarshal
		[PInvokeData("objidl.h", MSDNShortId = "6C82B08D-C8AF-4FB6-988C-CD7F9BABEE92")]
		[ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("ecc8691b-c1db-4dc0-855e-65f6c551af49")]
		public interface INoMarshal
		{
		}

		/// <summary>Performs various operations on contexts.</summary>
		/// <seealso cref="IContext"/>
		// https://docs.microsoft.com/en-us/windows/desktop/api/objidl/nn-objidl-iobjcontext
		[PInvokeData("objidl.h", MSDNShortId = "983615a1-cfa2-4137-8c7e-42e2ef6923a8")]
		[ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("000001c6-0000-0000-C000-000000000046")]
		public interface IObjContext : IContext
		{
			/// <summary>Adds the specified context property to the object context.</summary>
			/// <param name="rpolicyId">A GUID that uniquely identifies this context property.</param>
			/// <param name="flags">This parameter is reserved and must be zero.</param>
			/// <param name="pUnk">A pointer to the context property to be added.</param>
			// https://docs.microsoft.com/en-us/windows/desktop/api/objidl/nf-objidl-icontext-setproperty HRESULT SetProperty( REFGUID
			// rpolicyId, CPFLAGS flags, IUnknown *pUnk );
			new void SetProperty(in Guid rpolicyId, [Optional] uint flags, [In, MarshalAs(UnmanagedType.IUnknown)] object pUnk);

			/// <summary>Removes the specified context property from the context.</summary>
			/// <param name="rPolicyId">The GUID that uniquely identifies the context property to be removed.</param>
			// https://docs.microsoft.com/en-us/windows/desktop/api/objidl/nf-objidl-icontext-removeproperty HRESULT RemoveProperty( REFGUID
			// rPolicyId );
			new void RemoveProperty(in Guid rPolicyId);

			/// <summary>Retrieves the specified context property from the context.</summary>
			/// <param name="rGuid">The GUID that uniquely identifies the context property to be retrieved.</param>
			/// <param name="pFlags">The address of the variable that receives the flags associated with the property.</param>
			/// <returns>The address of the variable that receives the IUnknown interface pointer of the requested context property.</returns>
			// https://docs.microsoft.com/en-us/windows/desktop/api/objidl/nf-objidl-icontext-getproperty HRESULT GetProperty( REFGUID
			// rGuid, CPFLAGS *pFlags, IUnknown **ppUnk );
			[return: MarshalAs(UnmanagedType.IUnknown)]
			new object GetProperty(in Guid rGuid, out uint pFlags);

			/// <summary>
			/// Returns an IEnumContextProps interface pointer that can be used to enumerate the context properties in this context.
			/// </summary>
			/// <returns>The address of the variable that receives the new IEnumContextProps interface pointer.</returns>
			// https://docs.microsoft.com/en-us/windows/desktop/api/objidl/nf-objidl-icontext-enumcontextprops HRESULT EnumContextProps(
			// IEnumContextProps **ppEnumContextProps );
			new IEnumContextProps EnumContextProps();

			/// <summary/>
			void Reserved1();

			/// <summary/>
			void Reserved2();

			/// <summary/>
			void Reserved3();

			/// <summary/>
			void Reserved4();

			/// <summary/>
			void Reserved5();

			/// <summary/>
			void Reserved6();

			/// <summary/>
			void Reserved7();
		}

		/// <summary>Specifies the process initialization time-out interval.</summary>
		// https://docs.microsoft.com/en-us/windows/win32/api/objidl/nn-objidl-iprocessinitcontrol
		[PInvokeData("objidl.h", MSDNShortId = "NN:objidl.IProcessInitControl")]
		[ComImport, Guid("72380d55-8d2b-43a3-8513-2b6ef31434e9"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
		public interface IProcessInitControl
		{
			/// <summary>Sets the process initialization time-out.</summary>
			/// <param name="dwSecondsRemaining">
			/// The number of seconds after this method is called before process initialization times out.
			/// </param>
			/// <returns>This method can return the standard return values E_INVALIDARG, E_OUTOFMEMORY, E_UNEXPECTED, E_FAIL, and S_OK.</returns>
			// https://docs.microsoft.com/en-us/windows/win32/api/objidlbase/nf-objidlbase-iprocessinitcontrol-resetinitializertimeout
			// HRESULT ResetInitializerTimeout( DWORD dwSecondsRemaining );
			[PreserveSig]
			HRESULT ResetInitializerTimeout(uint dwSecondsRemaining);
		}

		/// <summary>Provides custom methods for the creation of COM object proxies and stubs. This interface is not marshalable.</summary>
		// https://docs.microsoft.com/en-us/windows/win32/api/objidl/nn-objidl-ipsfactorybuffer
		[PInvokeData("objidl.h", MSDNShortId = "NN:objidl.IPSFactoryBuffer")]
		[ComImport, Guid("D5F569D0-593B-101A-B569-08002B2DBF7A"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
		public interface IPSFactoryBuffer
		{
			/// <summary>Creates a proxy for the specified remote interface.</summary>
			/// <param name="pUnkOuter">A controlling IUnknown interface; used for aggregation.</param>
			/// <param name="riid">The identifier of the interface to proxy.</param>
			/// <param name="ppProxy">A pointer to an IRpcProxyBuffer interface to control marshaling.</param>
			/// <param name="ppv">A pointer to the interface specified by riid.</param>
			/// <returns>This method can return the standard return values E_INVALIDARG, E_OUTOFMEMORY, E_UNEXPECTED, E_FAIL, and S_OK.</returns>
			/// <remarks>The IUnknown implementation of the IRpcProxyBuffer interface must not delegate to the outer controlling <c>IUnknown</c>.</remarks>
			// https://docs.microsoft.com/en-us/windows/win32/api/objidlbase/nf-objidlbase-ipsfactorybuffer-createproxy HRESULT CreateProxy(
			// IUnknown *pUnkOuter, REFIID riid, IRpcProxyBuffer **ppProxy, void **ppv );
			[PreserveSig]
			HRESULT CreateProxy([In, MarshalAs(UnmanagedType.IUnknown)] object pUnkOuter, in Guid riid, out IRpcProxyBuffer ppProxy,
				[MarshalAs(UnmanagedType.IUnknown, IidParameterIndex = 1)] out object ppv);

			/// <summary>Creates a stub for the remote use of the specified interface.</summary>
			/// <param name="riid">The identifier of the interface for which a stub is to be created.</param>
			/// <param name="pUnkServer">A controlling IUnknown interface; used for aggregation.</param>
			/// <param name="ppStub">A pointer to an IRpcStubBuffer interface pointer to control marshaling.</param>
			/// <returns>This method can return the standard return values E_INVALIDARG, E_OUTOFMEMORY, E_UNEXPECTED, E_FAIL, and S_OK.</returns>
			// https://docs.microsoft.com/en-us/windows/win32/api/objidlbase/nf-objidlbase-ipsfactorybuffer-createstub HRESULT CreateStub(
			// REFIID riid, IUnknown *pUnkServer, IRpcStubBuffer **ppStub );
			[PreserveSig]
			HRESULT CreateStub(in Guid riid, [In, Optional, MarshalAs(UnmanagedType.IUnknown)] object pUnkServer, out IRpcStubBuffer ppStub);
		}

		/// <summary>Marshals data between a COM client proxy and a COM server stub.</summary>
		// https://docs.microsoft.com/en-us/windows/win32/api/objidl/nn-objidl-irpcchannelbuffer
		[PInvokeData("objidl.h", MSDNShortId = "NN:objidl.IRpcChannelBuffer")]
		[ComImport, Guid("D5F56B60-593B-101A-B569-08002B2DBF7A"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
		public interface IRpcChannelBuffer
		{
			/// <summary>Retrieves a buffer into which data can be marshaled for transmission.</summary>
			/// <param name="pMessage">A pointer to an RPCOLEMESSAGE data structure.</param>
			/// <param name="riid">A reference to the identifier of the interface to be marshaled.</param>
			/// <returns>This method can return the standard return values E_INVALIDARG, E_OUTOFMEMORY, E_UNEXPECTED, E_FAIL, and S_OK.</returns>
			// https://docs.microsoft.com/en-us/windows/win32/api/objidl/nf-objidl-irpcchannelbuffer-getbuffer HRESULT GetBuffer(
			// RPCOLEMESSAGE *pMessage, REFIID riid );
			[PreserveSig]
			HRESULT GetBuffer(ref RPCOLEMESSAGE pMessage, in Guid riid);

			/// <summary>Sends a method invocation across an RPC channel to the server stub.</summary>
			/// <param name="pMessage">A pointer to an RPCOLEMESSAGE structure that has been populated with marshaled data.</param>
			/// <param name="pStatus">If not <c>NULL</c>, set to 0 on successful execution.</param>
			/// <returns>This method can return the standard return values E_INVALIDARG, E_OUTOFMEMORY, E_UNEXPECTED, E_FAIL, and S_OK.</returns>
			/// <remarks>
			/// Before invoking this method, the GetBuffer method must have been invoked to allocate a channel buffer. Upon return, the
			/// <c>dataRepresentation</c> buffer of the RPCOLEMESSAGE structure will have been modified to include the data returned by the
			/// method invoked on the server. If the invocation was successful, the RPC channel buffer has been freed; otherwise the caller
			/// must free it explicitly by calling FreeBuffer.
			/// </remarks>
			// https://docs.microsoft.com/en-us/windows/win32/api/objidlbase/nf-objidlbase-irpcchannelbuffer-sendreceive HRESULT
			// SendReceive( RPCOLEMESSAGE *pMessage, ULONG *pStatus );
			[PreserveSig]
			HRESULT SendReceive(ref RPCOLEMESSAGE pMessage, [Out, Optional] IntPtr pStatus);

			/// <summary>Frees a previously allocated RPC channel buffer.</summary>
			/// <param name="pMessage">A pointer to an RPCOLEMESSAGE data structure.</param>
			/// <returns>This method can return the standard return values E_INVALIDARG, E_OUTOFMEMORY, E_UNEXPECTED, E_FAIL, and S_OK.</returns>
			// https://docs.microsoft.com/en-us/windows/win32/api/objidlbase/nf-objidlbase-irpcchannelbuffer-freebuffer HRESULT FreeBuffer(
			// RPCOLEMESSAGE *pMessage );
			[PreserveSig]
			HRESULT FreeBuffer(ref RPCOLEMESSAGE pMessage);

			/// <summary>Retrieves the destination context for the RPC channel.</summary>
			/// <param name="pdwDestContext">
			/// The destination context in which the interface is unmarshaled. Possible values come from the MSHCTX enumeration.
			/// </param>
			/// <param name="ppvDestContext">This parameter is reserved and must be <c>NULL</c>.</param>
			/// <returns>This method can return the standard return values E_INVALIDARG, E_OUTOFMEMORY, E_UNEXPECTED, E_FAIL, and S_OK.</returns>
			// https://docs.microsoft.com/en-us/windows/win32/api/objidl/nf-objidl-irpcchannelbuffer-getdestctx HRESULT GetDestCtx( DWORD
			// *pdwDestContext, void **ppvDestContext );
			[PreserveSig]
			HRESULT GetDestCtx(out MSHCTX pdwDestContext, out IntPtr ppvDestContext);

			/// <summary>Determines whether the RPC channel is connected.</summary>
			/// <returns>If the RPC channel exists, the return value is <c>TRUE</c>. Otherwise, it is <c>FALSE</c>.</returns>
			// https://docs.microsoft.com/en-us/windows/win32/api/objidlbase/nf-objidlbase-irpcchannelbuffer-isconnected HRESULT IsConnected();
			[PreserveSig]
			HRESULT IsConnected();
		}

		/// <summary>
		/// Enables callers to set or query the values of various properties that control how COM handles remote procedure calls (RPC).
		/// </summary>
		/// <remarks>
		/// <para>
		/// Using this interface, callers can set or query the COMBND_RPCTIMEOUT property, which controls how long your machine will attempt
		/// to establish RPC communications with another before failing. The property can have any one of the values enumerated in the
		/// following table.
		/// </para>
		/// <list type="table">
		/// <listheader>
		/// <term>Value</term>
		/// <term>Description</term>
		/// </listheader>
		/// <item>
		/// <term>RPC_C_BINDING_INFINITE_TIMEOUT</term>
		/// <term>Keep trying to establish communications with no timeout.</term>
		/// </item>
		/// <item>
		/// <term>RPC_C_BINDING_MIN_TIMEOUT</term>
		/// <term>Try to establish communications for the minimum time required by the protocol. This value favors performance over reliability.</term>
		/// </item>
		/// <item>
		/// <term>RPC_C_BINDING_DEFAULT_TIMEOUT</term>
		/// <term>Try to establish communications for the default time. The value strikes a balance between performance and reliability.</term>
		/// </item>
		/// <item>
		/// <term>RPC_C_BINDING_MAX_TIMEOUT</term>
		/// <term>Try to establish communications for the maximum time allowed by the protocol. This value favors reliability over performance.</term>
		/// </item>
		/// </list>
		/// </remarks>
		// https://docs.microsoft.com/en-us/windows/win32/api/objidl/nn-objidl-irpcoptions
		[PInvokeData("objidl.h", MSDNShortId = "NN:objidl.IRpcOptions")]
		[ComImport, Guid("00000144-0000-0000-C000-000000000046"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
		public interface IRpcOptions
		{
			/// <summary>Sets the value of an RPC binding option property.</summary>
			/// <param name="pPrx">A pointer to the proxy whose property is being set.</param>
			/// <param name="dwProperty">An identifier of the property to be set, which must be COMBND_RPCTIMEOUT.</param>
			/// <param name="dwValue">The new value of the property.</param>
			/// <returns>This method can return the standard return values E_INVALIDARG, E_OUTOFMEMORY, E_UNEXPECTED, E_FAIL, and S_OK.</returns>
			/// <remarks>See IRpcOptions for a table of the possible values of the COMBND_RPCTIMEOUT property.</remarks>
			// https://docs.microsoft.com/en-us/windows/win32/api/objidl/nf-objidl-irpcoptions-set HRESULT Set( IUnknown *pPrx,
			// RPCOPT_PROPERTIES dwProperty, ULONG_PTR dwValue );
			[PreserveSig]
			HRESULT Set([In, MarshalAs(UnmanagedType.IUnknown)] object pPrx, RPCOPT_PROPERTIES dwProperty, [In] IntPtr dwValue);

			/// <summary>Retrieves the value of an RPC binding option property.</summary>
			/// <param name="pPrx">A pointer to the proxy whose property is being queried.</param>
			/// <param name="dwProperty">
			/// An identifier of the property to be queried, which must be COMBND_RPCTIMEOUT or COMBND_SERVER_LOCALITY (this flag is
			/// available starting with Windows Server 2003.)
			/// </param>
			/// <param name="pdwValue">A pointer to the property value.</param>
			/// <returns>This method can return the standard return values E_INVALIDARG, E_OUTOFMEMORY, E_UNEXPECTED, E_FAIL, and S_OK.</returns>
			/// <remarks>
			/// <para>
			/// While the COMBND_RPCTIMEOUT property can also be set using the Set method, the COMBND_SERVER_LOCALITY property can only be queried.
			/// </para>
			/// <para>See IRpcOptions for a table of the possible values of the COMBND_RPCTIMEOUT property.</para>
			/// <para>
			/// The possible values of the COMBND_SERVER_LOCALITY property, which describes the degree of remoteness of the RPC connection,
			/// are enumerated in the following table.
			/// </para>
			/// <list type="table">
			/// <listheader>
			/// <term>Value</term>
			/// <term>Description</term>
			/// </listheader>
			/// <item>
			/// <term>SERVER_LOCALITY_PROCESS_LOCAL</term>
			/// <term>The counterpart is in the same process as the client.</term>
			/// </item>
			/// <item>
			/// <term>SERVER_LOCALITY_MACHINE_LOCAL</term>
			/// <term>The counterpart is on the same computer as the client but in a different process.</term>
			/// </item>
			/// <item>
			/// <term>SERVER_LOCALITY_REMOTE</term>
			/// <term>The counterpart is on a remote computer.</term>
			/// </item>
			/// </list>
			/// </remarks>
			// https://docs.microsoft.com/en-us/windows/win32/api/objidlbase/nf-objidlbase-irpcoptions-query HRESULT Query( IUnknown *pPrx,
			// RPCOPT_PROPERTIES dwProperty, ULONG_PTR *pdwValue );
			[PreserveSig]
			HRESULT Query([In, MarshalAs(UnmanagedType.IUnknown)] object pPrx, [In] RPCOPT_PROPERTIES dwProperty, out IntPtr pdwValue);
		}

		/// <summary>Controls the RPC proxy used to marshal data between COM components.</summary>
		// https://docs.microsoft.com/en-us/windows/win32/api/objidl/nn-objidl-irpcproxybuffer
		[PInvokeData("objidl.h", MSDNShortId = "NN:objidl.IRpcProxyBuffer")]
		[ComImport, Guid("D5F56A34-593B-101A-B569-08002B2DBF7A"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
		public interface IRpcProxyBuffer
		{
			/// <summary>Initializes a client proxy, binding it to the specified RPC channel.</summary>
			/// <param name="pRpcChannelBuffer">A pointer to the IRpcChannelBuffer interface that the proxy uses to marshal data.</param>
			/// <returns>This method can return the standard return values E_INVALIDARG, E_OUTOFMEMORY, E_UNEXPECTED, E_FAIL, and S_OK.</returns>
			// https://docs.microsoft.com/en-us/windows/win32/api/objidlbase/nf-objidlbase-irpcproxybuffer-connect HRESULT Connect(
			// IRpcChannelBuffer *pRpcChannelBuffer );
			[PreserveSig]
			HRESULT Connect([In] IRpcChannelBuffer pRpcChannelBuffer);

			/// <summary>Disconnects a client proxy from any RPC channel to which it is connected.</summary>
			/// <returns>None</returns>
			// https://docs.microsoft.com/en-us/windows/win32/api/objidlbase/nf-objidlbase-irpcproxybuffer-disconnect void Disconnect();
			[PreserveSig]
			void Disconnect();
		}

		/// <summary>Controls the RPC stub used to marshal data between COM components.</summary>
		// https://docs.microsoft.com/en-us/windows/win32/api/objidl/nn-objidl-irpcstubbuffer
		[PInvokeData("objidl.h", MSDNShortId = "NN:objidl.IRpcStubBuffer")]
		[ComImport, Guid("D5F56AFC-593B-101A-B569-08002B2DBF7A"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
		public interface IRpcStubBuffer
		{
			/// <summary>Initializes a server stub, binding it to the specified interface.</summary>
			/// <param name="pUnkServer">A pointer to the interface.</param>
			/// <returns>This method can return the standard return values E_INVALIDARG, E_OUTOFMEMORY, E_UNEXPECTED, E_FAIL, and S_OK.</returns>
			// https://docs.microsoft.com/en-us/windows/win32/api/objidl/nf-objidl-irpcstubbuffer-connect HRESULT Connect( IUnknown
			// *pUnkServer );
			[PreserveSig]
			HRESULT Connect([In, MarshalAs(UnmanagedType.IUnknown)] object pUnkServer);

			/// <summary>Disconnects a server stub from any interface to which it is connected.</summary>
			/// <returns>None</returns>
			// https://docs.microsoft.com/en-us/windows/win32/api/objidl/nf-objidl-irpcstubbuffer-disconnect void Disconnect();
			[PreserveSig]
			void Disconnect();

			/// <summary>Invokes the interface that a stub represents.</summary>
			/// <param name="_prpcmsg">A pointer to an RPCOLEMESSAGE data structure containing the marshaled invocation arguments.</param>
			/// <param name="_pRpcChannelBuffer">A pointer to an IRpcChannelBuffer interface that controls an RPC marshaling channel.</param>
			/// <returns>This method can return the standard return values E_INVALIDARG, E_OUTOFMEMORY, E_UNEXPECTED, E_FAIL, and S_OK.</returns>
			// https://docs.microsoft.com/en-us/windows/win32/api/objidlbase/nf-objidlbase-irpcstubbuffer-invoke HRESULT Invoke(
			// RPCOLEMESSAGE *_prpcmsg, IRpcChannelBuffer *_pRpcChannelBuffer );
			[PreserveSig]
			HRESULT Invoke(ref RPCOLEMESSAGE _prpcmsg, [In] IRpcChannelBuffer _pRpcChannelBuffer);

			/// <summary>Determines whether a stub is designed to handle the unmarshaling of a particular interface.</summary>
			/// <param name="riid">The IID of the interface. This parameter cannot be IID_IUnknown.</param>
			/// <returns>
			/// If the stub can handle the indicated interface, then this method returns an IRpcStubBuffer pointer for that interface;
			/// otherwise, it returns <c>NULL</c>.
			/// </returns>
			/// <remarks>
			/// <para>
			/// When presented with the need to remote a new IID on a given object, the RPC run time typically calls this method on all the
			/// presently-connected interface stubs in an attempt to locate one that can handle the marshaling for the request before it
			/// goes to the trouble of creating a new stub.
			/// </para>
			/// <para>
			/// As in IPSFactoryBuffer::CreateStub, if a stub is presently connected to a server object, then not only must this method
			/// verify that the stub can handle the indicated interface, but it must also verify (using QueryInterface) that the connected
			/// server object in fact supports the indicated interface. Depending on the IID and previous interface servicing requests, it
			/// may have already done so.
			/// </para>
			/// </remarks>
			// https://docs.microsoft.com/en-us/windows/win32/api/objidl/nf-objidl-irpcstubbuffer-isiidsupported IRpcStubBuffer *
			// IsIIDSupported( REFIID riid );
			[PreserveSig]
			IRpcStubBuffer IsIIDSupported(in Guid riid);

			/// <summary>Retrieves the total number of references that a stub has on the server object to which it is connected.</summary>
			/// <returns>This method returns the total number of references that a stub has on the server object to which it is connected.</returns>
			// https://docs.microsoft.com/en-us/windows/win32/api/objidl/nf-objidl-irpcstubbuffer-countrefs ULONG CountRefs();
			[PreserveSig]
			uint CountRefs();

			/// <summary>Retrieves a pointer to the interface that a stub represents.</summary>
			/// <param name="ppv">A pointer to the interface that the stub represents.</param>
			/// <returns>This method can return the standard return values E_INVALIDARG, E_OUTOFMEMORY, E_UNEXPECTED, E_FAIL, and S_OK.</returns>
			// https://docs.microsoft.com/en-us/windows/win32/api/objidl/nf-objidl-irpcstubbuffer-debugserverqueryinterface HRESULT
			// DebugServerQueryInterface( void **ppv );
			[PreserveSig]
			HRESULT DebugServerQueryInterface(out IntPtr ppv);

			/// <summary>Releases an interface pointer that was previously returned by DebugServerQueryInterface.</summary>
			/// <param name="pv">A pointer to the interface that the caller no longer needs.</param>
			/// <returns>None</returns>
			// https://docs.microsoft.com/en-us/windows/win32/api/objidl/nf-objidl-irpcstubbuffer-debugserverrelease void
			// DebugServerRelease( void *pv );
			[PreserveSig]
			void DebugServerRelease([In] IntPtr pv);
		}

		/// <summary>
		/// The <c>ISequentialStream</c> interface supports simplified sequential access to stream objects. The IStream interface inherits
		/// its Read and Write methods from <c>ISequentialStream</c>.
		/// </summary>
		// https://docs.microsoft.com/en-us/windows/desktop/api/objidl/nn-objidl-isequentialstream
		[PInvokeData("objidlbase.h", MSDNShortId = "c1d33800-d2f1-4942-92fa-e115f524c23c")]
		[ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("0c733a30-2a1c-11ce-ade5-00aa0044773d")]
		public interface ISequentialStream
		{
			/// <summary>
			/// The <c>Read</c> method reads a specified number of bytes from the stream object into memory, starting at the current seek pointer.
			/// </summary>
			/// <param name="pv">A pointer to the buffer which the stream data is read into.</param>
			/// <param name="cb">The number of bytes of data to read from the stream object.</param>
			/// <param name="pcbRead">
			/// <para>A pointer to a <c>ULONG</c> variable that receives the actual number of bytes read from the stream object.</para>
			/// <para><c>Note</c> The number of bytes read may be zero.</para>
			/// </param>
			/// <remarks>
			/// <para>
			/// This method reads bytes from this stream object into memory. The stream object must be opened in <c>STGM_READ</c> mode. This
			/// method adjusts the seek pointer by the actual number of bytes read.
			/// </para>
			/// <para>The number of bytes actually read is also returned in the pcbRead parameter.</para>
			/// <para>Notes to Callers</para>
			/// <para>
			/// The actual number of bytes read can be less than the number of bytes requested if an error occurs or if the end of the
			/// stream is reached during the read operation. The number of bytes returned should always be compared to the number of bytes
			/// requested. If the number of bytes returned is less than the number of bytes requested, it usually means the <c>Read</c>
			/// method attempted to read past the end of the stream.
			/// </para>
			/// <para>The application should handle both a returned error and <c>S_OK</c> return values on end-of-stream read operations.</para>
			/// </remarks>
			// https://docs.microsoft.com/en-us/windows/desktop/api/objidl/nf-objidl-isequentialstream-read HRESULT Read( void *pv, ULONG
			// cb, ULONG *pcbRead );
			[PInvokeData("objidl.h", MSDNShortId = "934a90bb-5ed0-4d80-9906-352ad8586655")]
			[PreserveSig]
			HRESULT Read(byte[] pv, uint cb, out uint pcbRead);

			/// <summary>
			/// The <c>Write</c> method writes a specified number of bytes into the stream object starting at the current seek pointer.
			/// </summary>
			/// <param name="pv">
			/// A pointer to the buffer that contains the data that is to be written to the stream. A valid pointer must be provided for
			/// this parameter even when cb is zero.
			/// </param>
			/// <param name="cb">The number of bytes of data to attempt to write into the stream. This value can be zero.</param>
			/// <param name="pcbWritten">
			/// A pointer to a <c>ULONG</c> variable where this method writes the actual number of bytes written to the stream object. The
			/// caller can set this pointer to <c>NULL</c>, in which case this method does not provide the actual number of bytes written.
			/// </param>
			/// <remarks>
			/// <para>
			/// <c>ISequentialStream::Write</c> writes the specified data to a stream object. The seek pointer is adjusted for the number of
			/// bytes actually written. The number of bytes actually written is returned in the pcbWritten parameter. If the byte count is
			/// zero bytes, the write operation has no effect.
			/// </para>
			/// <para>
			/// If the seek pointer is currently past the end of the stream and the byte count is nonzero, this method increases the size of
			/// the stream to the seek pointer and writes the specified bytes starting at the seek pointer. The fill bytes written to the
			/// stream are not initialized to any particular value. This is the same as the end-of-file behavior in the MS-DOS FAT file system.
			/// </para>
			/// <para>
			/// With a zero byte count and a seek pointer past the end of the stream, this method does not create the fill bytes to increase
			/// the stream to the seek pointer. In this case, you must call the IStream::SetSize method to increase the size of the stream
			/// and write the fill bytes.
			/// </para>
			/// <para>The pcbWritten parameter can have a value even if an error occurs.</para>
			/// <para>
			/// In the COM-provided implementation, stream objects are not sparse. Any fill bytes are eventually allocated on the disk and
			/// assigned to the stream.
			/// </para>
			/// </remarks>
			// https://docs.microsoft.com/en-us/windows/desktop/api/objidl/nf-objidl-isequentialstream-write HRESULT Write( const void *pv,
			// ULONG cb, ULONG *pcbWritten );
			[PInvokeData("objidl.h", MSDNShortId = "f0323dda-6c31-4411-bf20-9650162109c0")]
			[PreserveSig]
			HRESULT Write(byte[] pv, uint cb, out uint pcbWritten);
		}

		/// <summary>Used by a server to help authenticate the client and to manage impersonation of the client.</summary>
		// https://docs.microsoft.com/en-us/windows/win32/api/objidl/nn-objidl-iserversecurity
		[PInvokeData("objidl.h", MSDNShortId = "NN:objidl.IServerSecurity")]
		[ComImport, Guid("0000013E-0000-0000-C000-000000000046"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
		public interface IServerSecurity
		{
			/// <summary>Retrieves information about the client that invoked one of the server's methods.</summary>
			/// <param name="pAuthnSvc">
			/// A pointer to the current authentication service. This will be a single value taken from the list of authentication service
			/// constants. If the caller specifies <c>NULL</c>, the current authentication service is not retrieved.
			/// </param>
			/// <param name="pAuthzSvc">
			/// A pointer to a variable that receives the current authorization service. This will be a single value from the list of
			/// authorization constants. If the caller specifies <c>NULL</c>, the current authorization service is not retrieved.
			/// </param>
			/// <param name="pServerPrincName">
			/// The current principal name. The string will be allocated by the callee using CoTaskMemAlloc, and must be freed by the caller
			/// using CoTaskMemFree. By default, Schannel principal names will be in the msstd form. The fullsic form will be returned if
			/// EOAC_MAKE_FULLSIC is specified in the pCapabilities parameter. For more information on the msstd and fullsic forms, see
			/// Principal Names. If the caller specifies <c>NULL</c>, the current principal name is not retrieved.
			/// </param>
			/// <param name="pAuthnLevel">
			/// A pointer to a variable that receives the current authentication level. This will be a single value taken from the list of
			/// authentication level constants. If the caller specifies <c>NULL</c>, the current authentication level is not retrieved.
			/// </param>
			/// <param name="pImpLevel">This parameter must be <c>NULL</c>.</param>
			/// <param name="pPrivs">
			/// The privilege information for the client application. The format of the structure that the handle refers to depends on the
			/// authentication service. The application should not write or free the memory. The information is only valid for the duration
			/// of the current call. For NTLMSSP, and Kerberos, this is a SEC_WINNT_AUTH_IDENTITY or SEC_WINNT_AUTH_IDENTITY_EX structure.
			/// For Schannel, this is a CERT_CONTEXT structure that represents the client's certificate. If the client has no certificate,
			/// <c>NULL</c> is returned. If the caller specifies <c>NULL</c>, the current privilege information is not retrieved.
			/// </param>
			/// <param name="pCapabilities">
			/// The capabilities of the call. To request that the principal name be returned in fullsic form if Schannel is the
			/// authentication service, the caller can set the EOAC_MAKE_FULLSIC flag in this parameter. If the caller specifies
			/// <c>NULL</c>, the current capabilities are not retrieved.
			/// </param>
			/// <returns>This method can return the standard return values E_INVALIDARG, E_OUTOFMEMORY, and S_OK.</returns>
			/// <remarks>
			/// <c>QueryBlanket</c> is used by the server to find out about the client that invoked one of its methods. To get a pointer to
			/// IServerSecurity for the current call on the current thread, call CoGetCallContext, specifying IID_IServerSecurity. This
			/// interface pointer may only be used in the same apartment as the call for the duration of the call.
			/// </remarks>
			// https://docs.microsoft.com/en-us/windows/win32/api/objidl/nf-objidl-iserversecurity-queryblanket HRESULT QueryBlanket( DWORD
			// *pAuthnSvc, DWORD *pAuthzSvc, OLECHAR **pServerPrincName, DWORD *pAuthnLevel, DWORD *pImpLevel, void **pPrivs, DWORD
			// *pCapabilities );
			[PreserveSig]
			HRESULT QueryBlanket(out Rpc.RPC_C_AUTHN pAuthnSvc, out Rpc.RPC_C_AUTHZ pAuthzSvc, [MarshalAs(UnmanagedType.LPWStr)] out string pServerPrincName,
				out Rpc.RPC_C_AUTHN_LEVEL pAuthnLevel, out Rpc.RPC_C_IMP_LEVEL pImpLevel, out IntPtr pPrivs, ref uint pCapabilities);

			/// <summary>Enables a server to impersonate a client for the duration of a call.</summary>
			/// <returns>If the method succeeds, the return value is S_OK. Otherwise, it is E_FAIL.</returns>
			/// <remarks>
			/// <para>
			/// Usually, a method executes on a thread that uses the access token of the process. However, when impersonating a client, the
			/// server runs in the client's security context so that the server has access to the resources that the client has access to.
			/// When impersonation is necessary, the server calls the <c>ImpersonateClient</c> method to cause an access token representing
			/// the client's credentials to be assigned to the current thread. This thread token is used for access checks. RevertToSelf
			/// restores the current thread's access token.
			/// </para>
			/// <para>
			/// What the server can do on behalf of the client depends on the impersonation level set by the client, which is specified
			/// using one of the impersonation level constants. The server may impersonate the client on an encrypted call at identify,
			/// impersonate, or delegate level. For information about these levels of impersonation, see Impersonation Levels.
			/// </para>
			/// <para>
			/// The identity presented to a server called during impersonation depends on the type of cloaking value, if any, that is set by
			/// the client. For more information, see Cloaking.
			/// </para>
			/// <para>At the end of each method call, COM will call RevertToSelf if the application does not.</para>
			/// <para>
			/// Traditionally, impersonation information is not nested â€“ the last call to any impersonation mechanism overrides any
			/// previous impersonation. However, in the apartment model, impersonation is maintained during nested calls. Thus if the server
			/// A receives a call from B, impersonates, calls C, receives a call from D, impersonates, reverts, and receives the reply from
			/// C, the impersonation token will be set back to B, not A.
			/// </para>
			/// <para>For information on using impersonation with asynchronous calls, see Impersonation and Asynchronous Calls.</para>
			/// </remarks>
			// https://docs.microsoft.com/en-us/windows/win32/api/objidlbase/nf-objidlbase-iserversecurity-impersonateclient HRESULT ImpersonateClient();
			[PreserveSig]
			HRESULT ImpersonateClient();

			/// <summary>Restores the authentication information of a thread to what it was before impersonation began.</summary>
			/// <returns>If the method succeeds, the return value is S_OK. Otherwise, it is E_FAIL.</returns>
			/// <remarks>
			/// <para>
			/// <c>RevertToSelf</c> restores the authentication information on a thread to the authentication information on the thread
			/// before impersonation began. If the server does not call <c>RevertToSelf</c> before the end of the current call, it will be
			/// called automatically by COM.
			/// </para>
			/// <para>
			/// When ImpersonateClient is called on a thread that is not currently impersonating, COM saves the token currently on the
			/// thread. A subsequent call to <c>RevertToSelf</c> restores the saved token, and IsImpersonating will then return
			/// <c>FALSE</c>. This means that if a series of impersonation calls are made using different IServerSecurity objects,
			/// <c>RevertToSelf</c> will restore the token that was on the thread when the first call to <c>ImpersonateClient</c> was made.
			/// Also, only one <c>RevertToSelf</c> call is needed to undo any number of <c>ImpersonateClient</c> calls.
			/// </para>
			/// <para>
			/// This method will only revert impersonation changes made by ImpersonateClient. If the thread token is modified by other means
			/// (through the SetThreadToken or RpcImpersonateClient functions) the result of this function is undefined.
			/// </para>
			/// <para>
			/// <c>RevertToSelf</c> affects only the current method invocation. If there are nested method invocations, each invocation can
			/// have its own impersonation token and DCOM will correctly restore the impersonation token before returning to them
			/// (regardless of whether CoRevertToSelf or <c>RevertToSelf</c> was called).
			/// </para>
			/// <para>
			/// It is important to understand that an instance of IServerSecurity is valid on any thread in the apartment until the call
			/// represented by <c>IServerSecurity</c> completes. However, impersonation is local to a particular thread for the duration of
			/// the current call on that thread. Therefore, if two threads in the same apartment use the same <c>IServerSecurity</c>
			/// instance to call ImpersonateClient, one thread can call <c>RevertToSelf</c> without affecting the other.
			/// </para>
			/// </remarks>
			// https://docs.microsoft.com/en-us/windows/win32/api/objidl/nf-objidl-iserversecurity-reverttoself HRESULT RevertToSelf();
			[PreserveSig]
			HRESULT RevertToSelf();

			/// <summary>Indicates whether the server is currently impersonating the client.</summary>
			/// <returns>If the thread is currently impersonating, the return value is <c>TRUE</c>. Otherwise, it is <c>FALSE</c>.</returns>
			// https://docs.microsoft.com/en-us/windows/win32/api/objidlbase/nf-objidlbase-iserversecurity-isimpersonating BOOL IsImpersonating();
			[PreserveSig]
			[return: MarshalAs(UnmanagedType.Bool)]
			bool IsImpersonating();
		}

		/// <summary>Retrieves the CLSID identifying the handler to be used in the destination process during standard marshaling.</summary>
		/// <remarks>
		/// <para>
		/// An object that uses OLE's default implementation of IMarshal does not provide its own proxy but, by implementing
		/// <c>IStdMarshalInfo</c>, can nevertheless specify a handler to be loaded in the client process. Such a handler would typically
		/// handle certain requests in-process and use OLE's default marshaling to delegate others back to the original object.
		/// </para>
		/// <para>
		/// To create an instance of an object in some client process, COM must first determine whether the object uses default marshaling
		/// or its own implementation. If the object uses default marshaling, COM then queries the object to determine whether it uses a
		/// special handler or, simply, OLE's default proxy. To get the CLSID of the handler to be loaded, COM queries the object for
		/// <c>IStdMarshalInfo</c> and then the IPersist interface. If neither interface is supported, a standard handler is used.
		/// </para>
		/// </remarks>
		// https://docs.microsoft.com/en-us/windows/win32/api/objidl/nn-objidl-istdmarshalinfo
		[PInvokeData("objidl.h", MSDNShortId = "NN:objidl.IStdMarshalInfo")]
		[ComImport, Guid("00000018-0000-0000-C000-000000000046"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
		public interface IStdMarshalInfo
		{
			/// <summary>Retrieves the CLSID of the object handler to be used in the destination process during standard marshaling.</summary>
			/// <param name="dwDestContext">
			/// The destination context, that is, the process in which the unmarshaling will be done. Possible values are taken from the
			/// enumeration MSHCTX.
			/// </param>
			/// <param name="pvDestContext">This parameter must be <c>NULL</c>.</param>
			/// <param name="pClsid">A pointer to the handler's CLSID.</param>
			/// <returns>This method can return the standard return values E_INVALIDARG, E_OUTOFMEMORY, E_UNEXPECTED, and S_OK.</returns>
			/// <remarks>
			/// <para>Notes to Implementers</para>
			/// <para>
			/// Your implementation of <c>IStdMarshalInfo::GetClassForHandler</c> must return your own CLSID. This enables an object to be
			/// created by a different server.
			/// </para>
			/// </remarks>
			// https://docs.microsoft.com/en-us/windows/win32/api/objidl/nf-objidl-istdmarshalinfo-getclassforhandler HRESULT
			// GetClassForHandler( DWORD dwDestContext, void *pvDestContext, CLSID *pClsid );
			[PreserveSig]
			HRESULT GetClassForHandler([In] MSHCTX dwDestContext, [In, Optional] IntPtr pvDestContext, out Guid pClsid);
		}

		/// <summary>
		/// <para>
		/// The <c>IStream</c> interface lets you read and write data to stream objects. Stream objects contain the data in a structured
		/// storage object, where storages provide the structure. Simple data can be written directly to a stream but, most frequently,
		/// streams are elements nested within a storage object. They are similar to standard files.
		/// </para>
		/// <para>
		/// The <c>IStream</c> interface defines methods similar to the MS-DOS FAT file functions. For example, each stream object has its
		/// own access rights and a seek pointer. The main difference between a DOS file and a stream object is that in the latter case,
		/// streams are opened using an <c>IStream</c> interface pointer rather than a file handle.
		/// </para>
		/// <para>
		/// The methods in this interface present your object's data as a contiguous sequence of bytes that you can read or write. There are
		/// also methods for committing and reverting changes on streams that are open in transacted mode and methods for restricting access
		/// to a range of bytes in the stream.
		/// </para>
		/// <para>
		/// Streams can remain open for long periods of time without consuming file-system resources. The IUnknown::Release method is
		/// similar to a close function on a file. Once released, the stream object is no longer valid and cannot be used.
		/// </para>
		/// <para>
		/// Clients of asynchronous monikers can choose between a data-pull or data-push model for driving an asynchronous
		/// IMoniker::BindToStorage operation and for receiving asynchronous notifications. See URL Monikers for more information. The
		/// following table compares the behavior of asynchronous ISequentialStream::Read and IStream::Seek calls returned in
		/// IBindStatusCallback::OnDataAvailable in these two download models:
		/// </para>
		/// <list type="table">
		/// <listheader>
		/// <term>IStream method call</term>
		/// <term>Behavior in data-pull model</term>
		/// <term>Behavior in data-push model</term>
		/// </listheader>
		/// <item>
		/// <term>Read is called to read partial data (that is, not all the available data)</term>
		/// <term>
		/// Returns S_OK. The client must continue to read all available data before returning from IBindStatusCallback::OnDataAvailable or
		/// else the bind operation is blocked. (that is, read until S_FALSE or E_PENDING is returned)
		/// </term>
		/// <term>
		/// Returns S_OK. Even if the client returns from IBindStatusCallback::OnDataAvailable at this point the bind operation continues
		/// and IBindStatusCallback::OnDataAvailable will be called again repeatedly until the binding finishes.
		/// </term>
		/// </item>
		/// <item>
		/// <term>Read is called to read all the available data</term>
		/// <term>
		/// Returns E_PENDING if the bind operation has not completed, and IBindStatusCallback::OnDataAvailable will be called again when
		/// more data is available.
		/// </term>
		/// <term>Same as data-pull model.</term>
		/// </item>
		/// <item>
		/// <term>Read is called to read all the available data and the bind operation is over (end of file)</term>
		/// <term>Returns S_FALSE. There will be a subsequent call to IBindStatusCallback::OnDataAvailable with the grfBSC flag set to BSCF_LASTDATANOTIFICATION.</term>
		/// <term>Same as data-pull model.</term>
		/// </item>
		/// <item>
		/// <term>Seek is called</term>
		/// <term>Seek does not work in data-pull model</term>
		/// <term>Seek does not work in data-push model.</term>
		/// </item>
		/// </list>
		/// <para>
		/// For general information on this topic, see Asynchronous Monikers and Data-Pull-Model versus Data Push-Model for more specific
		/// information. Also, see Managing Memory Allocation for details on COM's rules for managing memory.
		/// </para>
		/// </summary>
		// https://docs.microsoft.com/en-us/windows/win32/api/objidl/nn-objidl-istream
		[PInvokeData("objidl.h", MSDNShortId = "NN:objidl.IStream")]
		[ComImport, Guid("0000000c-0000-0000-C000-000000000046"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
		public interface IStreamV : ISequentialStream
		{
			/// <summary>
			/// The <c>Read</c> method reads a specified number of bytes from the stream object into memory, starting at the current seek pointer.
			/// </summary>
			/// <param name="pv">A pointer to the buffer which the stream data is read into.</param>
			/// <param name="cb">The number of bytes of data to read from the stream object.</param>
			/// <param name="pcbRead">
			/// <para>A pointer to a <c>ULONG</c> variable that receives the actual number of bytes read from the stream object.</para>
			/// <para><c>Note</c> The number of bytes read may be zero.</para>
			/// </param>
			/// <remarks>
			/// <para>
			/// This method reads bytes from this stream object into memory. The stream object must be opened in <c>STGM_READ</c> mode. This
			/// method adjusts the seek pointer by the actual number of bytes read.
			/// </para>
			/// <para>The number of bytes actually read is also returned in the pcbRead parameter.</para>
			/// <para>Notes to Callers</para>
			/// <para>
			/// The actual number of bytes read can be less than the number of bytes requested if an error occurs or if the end of the
			/// stream is reached during the read operation. The number of bytes returned should always be compared to the number of bytes
			/// requested. If the number of bytes returned is less than the number of bytes requested, it usually means the <c>Read</c>
			/// method attempted to read past the end of the stream.
			/// </para>
			/// <para>The application should handle both a returned error and <c>S_OK</c> return values on end-of-stream read operations.</para>
			/// </remarks>
			// https://docs.microsoft.com/en-us/windows/desktop/api/objidl/nf-objidl-isequentialstream-read HRESULT Read( void *pv, ULONG
			// cb, ULONG *pcbRead );
			[PInvokeData("objidl.h", MSDNShortId = "934a90bb-5ed0-4d80-9906-352ad8586655")]
			[PreserveSig]
			new HRESULT Read(byte[] pv, uint cb, out uint pcbRead);

			/// <summary>
			/// The <c>Write</c> method writes a specified number of bytes into the stream object starting at the current seek pointer.
			/// </summary>
			/// <param name="pv">
			/// A pointer to the buffer that contains the data that is to be written to the stream. A valid pointer must be provided for
			/// this parameter even when cb is zero.
			/// </param>
			/// <param name="cb">The number of bytes of data to attempt to write into the stream. This value can be zero.</param>
			/// <param name="pcbWritten">
			/// A pointer to a <c>ULONG</c> variable where this method writes the actual number of bytes written to the stream object. The
			/// caller can set this pointer to <c>NULL</c>, in which case this method does not provide the actual number of bytes written.
			/// </param>
			/// <remarks>
			/// <para>
			/// <c>ISequentialStream::Write</c> writes the specified data to a stream object. The seek pointer is adjusted for the number of
			/// bytes actually written. The number of bytes actually written is returned in the pcbWritten parameter. If the byte count is
			/// zero bytes, the write operation has no effect.
			/// </para>
			/// <para>
			/// If the seek pointer is currently past the end of the stream and the byte count is nonzero, this method increases the size of
			/// the stream to the seek pointer and writes the specified bytes starting at the seek pointer. The fill bytes written to the
			/// stream are not initialized to any particular value. This is the same as the end-of-file behavior in the MS-DOS FAT file system.
			/// </para>
			/// <para>
			/// With a zero byte count and a seek pointer past the end of the stream, this method does not create the fill bytes to increase
			/// the stream to the seek pointer. In this case, you must call the IStream::SetSize method to increase the size of the stream
			/// and write the fill bytes.
			/// </para>
			/// <para>The pcbWritten parameter can have a value even if an error occurs.</para>
			/// <para>
			/// In the COM-provided implementation, stream objects are not sparse. Any fill bytes are eventually allocated on the disk and
			/// assigned to the stream.
			/// </para>
			/// </remarks>
			// https://docs.microsoft.com/en-us/windows/desktop/api/objidl/nf-objidl-isequentialstream-write HRESULT Write( const void *pv,
			// ULONG cb, ULONG *pcbWritten );
			[PInvokeData("objidl.h", MSDNShortId = "f0323dda-6c31-4411-bf20-9650162109c0")]
			[PreserveSig]
			new HRESULT Write(byte[] pv, uint cb, out uint pcbWritten);

			/// <summary>
			/// The <c>Seek</c> method changes the seek pointer to a new location. The new location is relative to either the beginning of
			/// the stream, the end of the stream, or the current seek pointer.
			/// </summary>
			/// <param name="dlibMove">
			/// The displacement to be added to the location indicated by the dwOrigin parameter. If dwOrigin is <c>STREAM_SEEK_SET</c>,
			/// this is interpreted as an unsigned value rather than a signed value.
			/// </param>
			/// <param name="dwOrigin">
			/// The origin for the displacement specified in dlibMove. The origin can be the beginning of the file (
			/// <c>STREAM_SEEK_SET</c>), the current seek pointer ( <c>STREAM_SEEK_CUR</c>), or the end of the file (
			/// <c>STREAM_SEEK_END</c>). For more information about values, see the STREAM_SEEK enumeration.
			/// </param>
			/// <param name="plibNewPosition">
			/// <para>A pointer to the location where this method writes the value of the new seek pointer from the beginning of the stream.</para>
			/// <para>You can set this pointer to <c>NULL</c>. In this case, this method does not provide the new seek pointer.</para>
			/// </param>
			/// <returns>This method can return one of these values.</returns>
			/// <remarks>
			/// <para>
			/// <c>IStream::Seek</c> changes the seek pointer so that subsequent read and write operations can be performed at a different
			/// location in the stream object. It is an error to seek before the beginning of the stream. It is not, however, an error to
			/// seek past the end of the stream. Seeking past the end of the stream is useful for subsequent write operations, as the stream
			/// byte range will be extended to the new seek position immediately before the write is complete.
			/// </para>
			/// <para>
			/// You can also use this method to obtain the current value of the seek pointer by calling this method with the dwOrigin
			/// parameter set to <c>STREAM_SEEK_CUR</c> and the dlibMove parameter set to 0 so that the seek pointer is not changed. The
			/// current seek pointer is returned in the plibNewPosition parameter.
			/// </para>
			/// </remarks>
			// https://docs.microsoft.com/en-us/windows/win32/api/objidl/nf-objidl-istream-seek HRESULT Seek( LARGE_INTEGER dlibMove, DWORD
			// dwOrigin, ULARGE_INTEGER *plibNewPosition );
			[PreserveSig]
			HRESULT Seek(long dlibMove, STREAM_SEEK dwOrigin, IntPtr plibNewPosition);

			/// <summary>The <c>SetSize</c> method changes the size of the stream object.</summary>
			/// <param name="libNewSize">Specifies the new size, in bytes, of the stream.</param>
			/// <returns>This method can return one of these values.</returns>
			/// <remarks>
			/// <para>
			/// <c>IStream::SetSize</c> changes the size of the stream object. Call this method to preallocate space for the stream. If the
			/// libNewSize parameter is larger than the current stream size, the stream is extended to the indicated size by filling the
			/// intervening space with bytes of undefined value. This operation is similar to the ISequentialStream::Write method if the
			/// seek pointer is past the current end of the stream.
			/// </para>
			/// <para>If the libNewSize parameter is smaller than the current stream, the stream is truncated to the indicated size.</para>
			/// <para>The seek pointer is not affected by the change in stream size.</para>
			/// <para>Calling <c>IStream::SetSize</c> can be an effective way to obtain a large chunk of contiguous space.</para>
			/// </remarks>
			// https://docs.microsoft.com/en-us/windows/win32/api/objidl/nf-objidl-istream-setsize HRESULT SetSize( ULARGE_INTEGER
			// libNewSize );
			[PreserveSig]
			HRESULT SetSize(long libNewSize);

			/// <summary>
			/// The <c>CopyTo</c> method copies a specified number of bytes from the current seek pointer in the stream to the current seek
			/// pointer in another stream.
			/// </summary>
			/// <param name="pstm">
			/// A pointer to the destination stream. The stream pointed to by pstm can be a new stream or a clone of the source stream.
			/// </param>
			/// <param name="cb">The number of bytes to copy from the source stream.</param>
			/// <param name="pcbRead">
			/// A pointer to the location where this method writes the actual number of bytes read from the source. You can set this pointer
			/// to <c>NULL</c>. In this case, this method does not provide the actual number of bytes read.
			/// </param>
			/// <param name="pcbWritten">
			/// A pointer to the location where this method writes the actual number of bytes written to the destination. You can set this
			/// pointer to <c>NULL</c>. In this case, this method does not provide the actual number of bytes written.
			/// </param>
			/// <returns>This method can return one of these values.</returns>
			/// <remarks>
			/// <para>
			/// The <c>CopyTo</c> method copies the specified bytes from one stream to another. It can also be used to copy a stream to
			/// itself. The seek pointer in each stream instance is adjusted for the number of bytes read or written. This method is
			/// equivalent to reading cb bytes into memory using ISequentialStream::Read and then immediately writing them to the
			/// destination stream using ISequentialStream::Write, although <c>IStream::CopyTo</c> will be more efficient.
			/// </para>
			/// <para>The destination stream can be a clone of the source stream created by calling the IStream::Clone method.</para>
			/// <para>
			/// If <c>IStream::CopyTo</c> returns an error, you cannot assume that the seek pointers are valid for either the source or
			/// destination. Additionally, the values of pcbRead and pcbWritten are not meaningful even though they are returned.
			/// </para>
			/// <para>If <c>IStream::CopyTo</c> returns successfully, the actual number of bytes read and written are the same.</para>
			/// <para>
			/// To copy the remainder of the source from the current seek pointer, specify the maximum large integer value for the cb
			/// parameter. If the seek pointer is the beginning of the stream, this operation copies the entire stream.
			/// </para>
			/// </remarks>
			// https://docs.microsoft.com/en-us/windows/win32/api/objidl/nf-objidl-istream-copyto HRESULT CopyTo( IStream *pstm,
			// ULARGE_INTEGER cb, ULARGE_INTEGER *pcbRead, ULARGE_INTEGER *pcbWritten );
			[PreserveSig]
			HRESULT CopyTo(IStream pstm, long cb, IntPtr pcbRead, IntPtr pcbWritten);

			/// <summary>
			/// The <c>Commit</c> method ensures that any changes made to a stream object open in transacted mode are reflected in the
			/// parent storage. If the stream object is open in direct mode, <c>IStream::Commit</c> has no effect other than flushing all
			/// memory buffers to the next-level storage object. The COM compound file implementation of streams does not support opening
			/// streams in transacted mode.
			/// </summary>
			/// <param name="grfCommitFlags">
			/// Controls how the changes for the stream object are committed. See the STGC enumeration for a definition of these values.
			/// </param>
			/// <returns>This method can return one of these values.</returns>
			/// <remarks>
			/// <para>
			/// The <c>Commit</c> method ensures that changes to a stream object opened in transacted mode are reflected in the parent
			/// storage. Changes that have been made to the stream since it was opened or last committed are reflected to the parent storage
			/// object. If the parent is opened in transacted mode, the parent may revert at a later time, rolling back the changes to this
			/// stream object. The compound file implementation does not support the opening of streams in transacted mode, so this method
			/// has very little effect other than to flush memory buffers. For more information, see IStream - Compound File Implementation.
			/// </para>
			/// <para>
			/// If the stream is open in direct mode, this method ensures that any memory buffers have been flushed out to the underlying
			/// storage object. This is much like a flush in traditional file systems.
			/// </para>
			/// <para>
			/// The <c>IStream::Commit</c> method is useful on a direct mode stream when the implementation of the IStream interface is a
			/// wrapper for underlying file system APIs. In this case, <c>IStream::Commit</c> would be connected to the file system's flush call.
			/// </para>
			/// </remarks>
			// https://docs.microsoft.com/en-us/windows/win32/api/objidl/nf-objidl-istream-commit HRESULT Commit( DWORD grfCommitFlags );
			[PreserveSig]
			HRESULT Commit(STGC grfCommitFlags);

			/// <summary>
			/// The <c>Revert</c> method discards all changes that have been made to a transacted stream since the last IStream::Commit
			/// call. On streams open in direct mode and streams using the COM compound file implementation of <c>IStream::Revert</c>, this
			/// method has no effect.
			/// </summary>
			/// <returns>This method can return one of these values.</returns>
			/// <remarks>The <c>Revert</c> method discards changes made to a transacted stream since the last commit operation.</remarks>
			// https://docs.microsoft.com/en-us/windows/win32/api/objidl/nf-objidl-istream-revert HRESULT Revert();
			[PreserveSig]
			HRESULT Revert();

			/// <summary>
			/// The <c>LockRegion</c> method restricts access to a specified range of bytes in the stream. Supporting this functionality is
			/// optional since some file systems do not provide it.
			/// </summary>
			/// <param name="libOffset">Integer that specifies the byte offset for the beginning of the range.</param>
			/// <param name="cb">Integer that specifies the length of the range, in bytes, to be restricted.</param>
			/// <param name="dwLockType">Specifies the restrictions being requested on accessing the range.</param>
			/// <returns>This method can return one of these values.</returns>
			/// <remarks>
			/// <para>
			/// The byte range of the stream can be extended. Locking an extended range for the stream is useful as a method of
			/// communication between different instances of the stream without changing data that is actually part of the stream.
			/// </para>
			/// <para>
			/// Three types of locking can be supported: locking to exclude other writers, locking to exclude other readers or writers, and
			/// locking that allows only one requester to obtain a lock on the given range, which is usually an alias for one of the other
			/// two lock types. A given stream instance might support either of the first two types, or both. The lock type is specified by
			/// dwLockType, using a value from the LOCKTYPE enumeration.
			/// </para>
			/// <para>
			/// Any region locked with <c>IStream::LockRegion</c> must later be explicitly unlocked by calling IStream::UnlockRegion with
			/// exactly the same values for the libOffset, cb, and dwLockType parameters. The region must be unlocked before the stream is
			/// released. Two adjacent regions cannot be locked separately and then unlocked with a single unlock call.
			/// </para>
			/// <para>Notes to Callers</para>
			/// <para>
			/// Since the type of locking supported is optional and can vary in different implementations of IStream, you must provide code
			/// to deal with the STG_E_INVALIDFUNCTION error.
			/// </para>
			/// <para>
			/// The <c>LockRegion</c> method has no effect in the compound file implementation, because the implementation does not support
			/// range locking.
			/// </para>
			/// <para>Notes to Implementers</para>
			/// <para>
			/// Support for this method is optional for implementations of stream objects since it may not be supported by the underlying
			/// file system. The type of locking supported is also optional. The STG_E_INVALIDFUNCTION error is returned if the requested
			/// type of locking is not supported.
			/// </para>
			/// </remarks>
			// https://docs.microsoft.com/en-us/windows/win32/api/objidl/nf-objidl-istream-lockregion HRESULT LockRegion( ULARGE_INTEGER
			// libOffset, ULARGE_INTEGER cb, DWORD dwLockType );
			[PreserveSig]
			HRESULT LockRegion(long libOffset, long cb, LOCKTYPE dwLockType);

			/// <summary>
			/// The <c>UnlockRegion</c> method removes the access restriction on a range of bytes previously restricted with IStream::LockRegion.
			/// </summary>
			/// <param name="libOffset">Specifies the byte offset for the beginning of the range.</param>
			/// <param name="cb">Specifies, in bytes, the length of the range to be restricted.</param>
			/// <param name="dwLockType">Specifies the access restrictions previously placed on the range.</param>
			/// <returns>This method can return one of these values.</returns>
			/// <remarks>
			/// <c>IStream::UnlockRegion</c> unlocks a region previously locked with the IStream::LockRegion method. Locked regions must
			/// later be explicitly unlocked by calling <c>IStream::UnlockRegion</c> with exactly the same values for the libOffset, cb, and
			/// dwLockType parameters. The region must be unlocked before the stream is released. Two adjacent regions cannot be locked
			/// separately and then unlocked with a single unlock call.
			/// </remarks>
			// https://docs.microsoft.com/en-us/windows/win32/api/objidl/nf-objidl-istream-unlockregion HRESULT UnlockRegion( ULARGE_INTEGER
			// libOffset, ULARGE_INTEGER cb, DWORD dwLockType );
			[PreserveSig]
			HRESULT UnlockRegion(long libOffset, long cb, LOCKTYPE dwLockType);

			/// <summary>The <c>Stat</c> method retrieves the STATSTG structure for this stream.</summary>
			/// <param name="pstatstg">Pointer to a STATSTG structure where this method places information about this stream object.</param>
			/// <param name="grfStatFlag">
			/// Specifies that this method does not return some of the members in the STATSTG structure, thus saving a memory allocation
			/// operation. Values are taken from the STATFLAG enumeration.
			/// </param>
			/// <returns>This method can return one of these values.</returns>
			/// <remarks>
			/// <c>IStream::Stat</c> retrieves a pointer to the STATSTG structure that contains information about this open stream. When
			/// this stream is within a structured storage and IStorage::EnumElements is called, it creates an enumerator object with the
			/// IEnumSTATSTG interface on it, which can be called to enumerate the storages and streams through the <c>STATSTG</c>
			/// structures associated with each of them.
			/// </remarks>
			// https://docs.microsoft.com/en-us/windows/win32/api/objidl/nf-objidl-istream-stat HRESULT Stat( STATSTG *pstatstg, DWORD
			// grfStatFlag );
			[PreserveSig]
			HRESULT Stat(out STATSTG pstatstg, STATFLAG grfStatFlag);

			/// <summary>
			/// The <c>Clone</c> method creates a new stream object with its own seek pointer that references the same bytes as the original stream.
			/// </summary>
			/// <param name="ppstm">
			/// When successful, pointer to the location of an IStream pointer to the new stream object. If an error occurs, this parameter
			/// is <c>NULL</c>.
			/// </param>
			/// <returns>This method can return one of these values.</returns>
			/// <remarks>
			/// <para>
			/// The <c>Clone</c> method creates a new stream object for accessing the same bytes but using a separate seek pointer. The new
			/// stream object sees the same data as the source-stream object. Changes written to one object are immediately visible in the
			/// other. Range locking is shared between the stream objects.
			/// </para>
			/// <para>
			/// The initial setting of the seek pointer in the cloned stream instance is the same as the current setting of the seek pointer
			/// in the original stream at the time of the clone operation.
			/// </para>
			/// </remarks>
			// https://docs.microsoft.com/en-us/windows/win32/api/objidl/nf-objidl-istream-clone HRESULT Clone( IStream **ppstm );
			[PreserveSig]
			HRESULT Clone(out IStream ppstm);
		}

		/// <summary>
		/// Used to dynamically load new DLL servers into an existing surrogate and free the surrogate when it is no longer needed.
		/// </summary>
		/// <remarks>
		/// A surrogate is an EXE process into which a DLL server can be loaded to give the DLL server the advantages of an EXE server
		/// without the coding overhead. It can also allow independent DLL servers to be located together within a single process, reducing
		/// the total number of processes needed. DLL servers are easy to write using standard development tools, like Microsoft Visual
		/// Studio, and running them in a surrogate process provides the benefits of an executable implementation, including fault
		/// isolation, the ability to serve multiple clients simultaneously, and allowing the server to provide services to remote clients
		/// in a distributed environment.
		/// </remarks>
		// https://docs.microsoft.com/en-us/windows/desktop/api/objidl/nn-objidl-isurrogate
		[PInvokeData("objidl.h", MSDNShortId = "fbed0514-3646-4744-aa7a-4a98f1a12cc0")]
		[ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("00000022-0000-0000-C000-000000000046")]
		public interface ISurrogate
		{
			/// <summary>
			/// Loads a DLL server into the implementing surrogate. COM calls this method when there is an activation request for the DLL
			/// server's class, if the class is registered as DllSurrogate.
			/// </summary>
			/// <param name="Clsid">The CLSID of the DLL server to be loaded.</param>
			/// <remarks>
			/// <para>Upon receiving a load request through <c>LoadDllServer</c>, the surrogate must perform the following steps:</para>
			/// <list type="number">
			/// <item>
			/// <term>Create a class factory object that supports IUnknown, IClassFactory, and IMarshal.</term>
			/// </item>
			/// <item>
			/// <term>Call CoRegisterClassObject to register the new class factory object as the class factory for the requested CLSID.</term>
			/// </item>
			/// </list>
			/// <para>
			/// This class factory's implementation of IClassFactory::CreateInstance will create an instance of the requested CLSID method
			/// by calling CoGetClassObject to get the class factory which creates an actual object for the given CLSID.
			/// </para>
			/// </remarks>
			// https://docs.microsoft.com/en-us/windows/desktop/api/objidl/nf-objidl-isurrogate-loaddllserver HRESULT LoadDllServer(
			// REFCLSID Clsid );
			void LoadDllServer(in Guid Clsid);

			/// <summary>Unloads a DLL server.</summary>
			/// <remarks>
			/// <para>
			/// COM calls <c>FreeSurrogate</c> when there are no more DLL servers running in the surrogate process. When
			/// <c>FreeSurrogate</c> is called, the method must properly revoke all of the class factories registered in the surrogate, and
			/// then cause the surrogate process to exit.
			/// </para>
			/// <para>
			/// Surrogate processes must call the CoFreeUnusedLibraries function periodically to unload DLL servers that are no longer in
			/// use. The surrogate process assumes this responsibility, which would normally be the client's responsibility.
			/// <c>CoFreeUnusedLibraries</c> calls the DllCanUnloadNow function on any loaded DLL servers. Because
			/// <c>CoFreeUnusedLibraries</c> depends on the existence and proper implementation of <c>DllCanUnloadNow</c> in DLL servers, it
			/// is not guaranteed to unload all DLL servers that should be unloaded --not every server implements <c>DllCanUnloadNow</c>,
			/// and this function is unreliable for free-threaded DLLs. Additionally, the surrogate has no way of being informed when all
			/// DLL servers are gone. COM, however, can determine when all DLL servers have been unloaded, and will then call the
			/// <c>FreeSurrogate</c> method.
			/// </para>
			/// </remarks>
			// https://docs.microsoft.com/en-us/windows/desktop/api/objidl/nf-objidl-isurrogate-freesurrogate HRESULT FreeSurrogate( );
			void FreeSurrogate();
		}

		/// <summary>
		/// Provides asynchronous communication between objects about the occurrence of an event. Objects that implement <c>ISynchronize</c>
		/// can receive indications that an event has occurred, and they can respond to queries about the event. In this way, clients can
		/// make sure that one request has been processed before they submit a subsequent request that depends on completion of the first one.
		/// </summary>
		// https://docs.microsoft.com/en-us/windows/win32/api/objidl/nn-objidl-isynchronize
		[PInvokeData("objidl.h", MSDNShortId = "NN:objidl.ISynchronize")]
		[ComImport, Guid("00000030-0000-0000-C000-000000000046"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
		public interface ISynchronize
		{
			/// <summary>
			/// Waits for the synchronization object to be signaled or for a specified timeout period to elapse, whichever comes first.
			/// </summary>
			/// <param name="dwFlags">The wait options. Possible values are taken from the COWAIT_FLAGS enumeration.</param>
			/// <param name="dwMilliseconds">
			/// The time this call will wait before returning, in milliseconds. If this parameter is INFINITE, the caller will wait until
			/// the synchronization object is signaled, no matter how long it takes. If this parameter is 0, the method returns immediately.
			/// </param>
			/// <returns>
			/// <para>
			/// This method can return the standard return values E_INVALIDARG, E_OUTOFMEMORY, and E_FAIL, as well as the following values.
			/// </para>
			/// <list type="table">
			/// <listheader>
			/// <term>Return code</term>
			/// <term>Description</term>
			/// </listheader>
			/// <item>
			/// <term>S_OK</term>
			/// <term>The synchronization object was signaled.</term>
			/// </item>
			/// <item>
			/// <term>RPC_E_CALLPENDING</term>
			/// <term>The time-out period elapsed before the synchronization object was signaled.</term>
			/// </item>
			/// </list>
			/// </returns>
			/// <remarks>
			/// If the caller is waiting in a single-thread apartment, <c>Wait</c> enters the COM modal loop. If the caller is waiting in a
			/// multithread apartment, the caller is blocked until <c>Wait</c> returns.
			/// </remarks>
			// https://docs.microsoft.com/en-us/windows/win32/api/objidl/nf-objidl-isynchronize-wait HRESULT Wait( DWORD dwFlags, DWORD
			// dwMilliseconds );
			[PreserveSig]
			HRESULT Wait(COWAIT_FLAGS dwFlags, uint dwMilliseconds);

			/// <summary>Sets the synchronization object to the signaled state and causes pending wait operations to return S_OK.</summary>
			/// <returns>This method returns S_OK to indicate that the method completed successfully.</returns>
			// https://docs.microsoft.com/en-us/windows/win32/api/objidlbase/nf-objidlbase-isynchronize-signal HRESULT Signal();
			[PreserveSig]
			HRESULT Signal();

			/// <summary>Sets the synchronization object to the nonsignaled state.</summary>
			/// <returns>This method returns S_OK to indicate that the method completed successfully.</returns>
			/// <remarks>
			/// <para>
			/// The ISynchronize::Wait method implemented on a standard event object (CLSID_StdEvent) automatically calls <c>Reset</c> when
			/// the synchronization object has been signaled.
			/// </para>
			/// <para>
			/// The implementation of ISynchronize::Wait on the manual reset event object (CLSID_ManualResetEvent) does not automatically
			/// call <c>Reset</c>. A server object usually calls <c>Reset</c> from a method that clients call after they detect that the
			/// synchronization object was signaled.
			/// </para>
			/// <para>
			/// In general, it is the server's responsibility to call <c>Reset</c>. If, however, the client needs to begin with the
			/// synchronization object in an unsignaled state, the client should call <c>Reset</c>.
			/// </para>
			/// </remarks>
			// https://docs.microsoft.com/en-us/windows/win32/api/objidlbase/nf-objidlbase-isynchronize-reset HRESULT Reset();
			[PreserveSig]
			HRESULT Reset();
		}

		/// <summary>Manages a group of unsignaled synchronization objects.</summary>
		// https://docs.microsoft.com/en-us/windows/win32/api/objidlbase/nn-objidlbase-isynchronizecontainer
		[PInvokeData("objidlbase.h", MSDNShortId = "NN:objidlbase.ISynchronizeContainer")]
		[ComImport, Guid("00000033-0000-0000-C000-000000000046"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
		public interface ISynchronizeContainer
		{
			/// <summary>Adds a synchronization object to the container.</summary>
			/// <param name="pSync">A pointer to the synchronization object to be added to the container. See ISynchronize.</param>
			/// <returns>
			/// <para>
			/// This method can return the standard return values E_INVALIDARG, E_OUTOFMEMORY, and E_FAIL, as well as the following values.
			/// </para>
			/// <list type="table">
			/// <listheader>
			/// <term>Return code</term>
			/// <term>Description</term>
			/// </listheader>
			/// <item>
			/// <term>S_OK</term>
			/// <term>The method completed successfully.</term>
			/// </item>
			/// <item>
			/// <term>RPC_E_OUT_OF_RESOURCES</term>
			/// <term>The synchronization object container is full.</term>
			/// </item>
			/// </list>
			/// </returns>
			/// <remarks>A synchronization container can hold pointers to as many as 63 synchronization objects.</remarks>
			// https://docs.microsoft.com/en-us/windows/win32/api/objidl/nf-objidl-isynchronizecontainer-addsynchronize HRESULT
			// AddSynchronize( ISynchronize *pSync );
			[PreserveSig]
			HRESULT AddSynchronize([In] ISynchronize pSync);

			/// <summary>
			/// Waits for any synchronization object in the container to be signaled or for a specified timeout period to elapse, whichever
			/// comes first.
			/// </summary>
			/// <param name="dwFlags">
			/// The wait options. Possible values are taken from the COWAIT_FLAGS enumeration. COWAIT_WAITALL is not a valid setting for
			/// this method.
			/// </param>
			/// <param name="dwTimeOut">
			/// The time this call will wait before returning, in milliseconds. If this parameter is INFINITE, the caller will wait until a
			/// synchronization object is signaled, no matter how long it takes. If this parameter is 0, the method returns immediately.
			/// </param>
			/// <param name="ppSync">
			/// A pointer to an ISynchronize interface pointer on the synchronization object that was signaled. This parameter cannot be <c>NULL</c>.
			/// </param>
			/// <returns>
			/// <para>
			/// This method can return the standard return values E_INVALIDARG, E_OUTOFMEMORY, and E_FAIL, as well as the following values.
			/// </para>
			/// <list type="table">
			/// <listheader>
			/// <term>Return code</term>
			/// <term>Description</term>
			/// </listheader>
			/// <item>
			/// <term>S_OK</term>
			/// <term>The synchronization object was signaled.</term>
			/// </item>
			/// <item>
			/// <term>RPC_E_TIMEOUT</term>
			/// <term>The time-out period elapsed before the synchronization object was signaled.</term>
			/// </item>
			/// <item>
			/// <term>RPC_E_NO_SYNC</term>
			/// <term>There are no synchronization objects in the container.</term>
			/// </item>
			/// </list>
			/// </returns>
			/// <remarks>
			/// If the caller is waiting in a single-thread apartment, <c>WaitMultiple</c> enters the COM modal loop. If the caller is
			/// waiting in a multithread apartment, the caller is blocked until <c>WaitMultiple</c> returns.
			/// </remarks>
			// https://docs.microsoft.com/en-us/windows/win32/api/objidl/nf-objidl-isynchronizecontainer-waitmultiple HRESULT WaitMultiple(
			// DWORD dwFlags, DWORD dwTimeOut, ISynchronize **ppSync );
			[PreserveSig]
			HRESULT WaitMultiple([In] COWAIT_FLAGS dwFlags, [In] uint dwTimeOut, out ISynchronize ppSync);
		}

		/// <summary>
		/// <para>Assigns an event handle to a synchronization object.</para>
		/// <para>
		/// The synchronization object can use a handle to manage its activities. For example, the wait functions use handles to identify
		/// the event they control. Thus, the logic of the ISynchronize::Signal method on an event synchronization object can pass its
		/// handle to the SetEvent function.
		/// </para>
		/// </summary>
		// https://docs.microsoft.com/en-us/windows/win32/api/objidlbase/nn-objidlbase-isynchronizeevent
		[PInvokeData("objidlbase.h", MSDNShortId = "NN:objidlbase.ISynchronizeEvent")]
		[ComImport, Guid("00000032-0000-0000-C000-000000000046"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
		public interface ISynchronizeEvent : ISynchronizeHandle
		{
			/// <summary>Assigns an event handle to a synchronization object.</summary>
			/// <param name="ph">A pointer to the event handle.</param>
			/// <returns>This method can return the standard return values E_INVALIDARG, E_OUTOFMEMORY, E_FAIL, and S_OK.</returns>
			// https://docs.microsoft.com/en-us/windows/win32/api/objidlbase/nf-objidlbase-isynchronizeevent-seteventhandle HRESULT
			// SetEventHandle( HANDLE *ph );
			[PreserveSig]
			HRESULT SetEventHandle(in HANDLE ph);
		}

		/// <summary>Retrieves a handle associated with a synchronization object.</summary>
		// https://docs.microsoft.com/en-us/windows/win32/api/objidl/nn-objidl-isynchronizehandle
		[PInvokeData("objidl.h", MSDNShortId = "NN:objidl.ISynchronizeHandle")]
		[ComImport, Guid("00000031-0000-0000-C000-000000000046"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
		public interface ISynchronizeHandle
		{
			/// <summary>Retrieves a handle to the synchronization object.</summary>
			/// <param name="ph">A pointer to the variable that receives a handle to the synchronization object.</param>
			/// <returns>This method can return the standard return values E_INVALIDARG, E_OUTOFMEMORY, E_FAIL, and S_OK.</returns>
			// https://docs.microsoft.com/en-us/windows/win32/api/objidlbase/nf-objidlbase-isynchronizehandle-gethandle HRESULT GetHandle(
			// HANDLE *ph );
			[PreserveSig]
			HRESULT GetHandle(out HANDLE ph);
		}

		/// <summary>Represents an interface in a query for multiple interfaces.</summary>
		/// <remarks>
		/// To optimize network performance, most remote activation functions take an array of <c>MULTI_QI</c> structures rather than just a
		/// single IID as input and a single pointer to the requested interface on the object as output, as do local activation functions.
		/// This allows a set of pointers to interfaces to be returned from the same object in a single round-trip to the server. In network
		/// scenarios, requesting multiple interfaces at the time of object construction can save considerable time over using a number of
		/// calls to QueryInterface for unique interfaces, each of which would require a round-trip to the server.
		/// </remarks>
		// https://docs.microsoft.com/en-us/windows/win32/api/objidl/ns-objidl-multi_qi typedef struct tagMULTI_QI { const IID *pIID;
		// IUnknown *pItf; HRESULT hr; } MULTI_QI;
		[PInvokeData("objidl.h", MSDNShortId = "NS:objidl.tagMULTI_QI")]
		[StructLayout(LayoutKind.Sequential)]
		public struct MULTI_QI
		{
			/// <summary>A pointer to an interface identifier.</summary>
			public GuidPtr pIID;

			/// <summary>A pointer to the interface requested in <c>pIID</c>. This member must be <c>NULL</c> on input.</summary>
			[MarshalAs(UnmanagedType.IUnknown)] public object pItf;

			/// <summary>
			/// The return value of the QueryInterface call to locate the requested interface. Common return values include S_OK and
			/// E_NOINTERFACE. This member must be 0 on input.
			/// </summary>
			public HRESULT hr;
		}

		/// <summary>Contains marshaling invocation arguments and return values between COM components.</summary>
		// https://docs.microsoft.com/en-us/windows/win32/api/objidlbase/ns-objidlbase-rpcolemessage typedef struct tagRPCOLEMESSAGE { void
		// *reserved1; RPCOLEDATAREP dataRepresentation; void *Buffer; ULONG cbBuffer; ULONG iMethod; void *reserved2[5]; ULONG rpcFlags; } RPCOLEMESSAGE;
		[PInvokeData("objidlbase.h", MSDNShortId = "NS:objidlbase.tagRPCOLEMESSAGE")]
		[StructLayout(LayoutKind.Sequential)]
		public struct RPCOLEMESSAGE
		{
			/// <summary>This member is reserved.</summary>
			public IntPtr reserved1;

			/// <summary>The data representation with which the data was marshaled.</summary>
			public uint dataRepresentation;

			/// <summary>A buffer for marshaled data.</summary>
			public IntPtr Buffer;

			/// <summary>The size of the buffer, in bytes.</summary>
			public uint cbBuffer;

			/// <summary>The number of the method to be invoked.</summary>
			public uint iMethod;

			/// <summary>This member is reserved.</summary>
			public IntPtr reserved2_1;

			/// <summary>This member is reserved.</summary>
			public IntPtr reserved2_2;

			/// <summary>This member is reserved.</summary>
			public IntPtr reserved2_3;

			/// <summary>This member is reserved.</summary>
			public IntPtr reserved2_4;

			/// <summary>This member is reserved.</summary>
			public IntPtr reserved2_5;

			/// <summary>Status flags for the RPC connection.</summary>
			public uint rpcFlags;
		}

		/// <summary>
		/// Identifies an authentication service, authorization service, and the authentication information for the specified authentication service.
		/// </summary>
		// https://docs.microsoft.com/en-us/windows/desktop/api/objidl/ns-objidl-tagsole_authentication_info typedef struct
		// tagSOLE_AUTHENTICATION_INFO { DWORD dwAuthnSvc; DWORD dwAuthzSvc; void *pAuthInfo; } SOLE_AUTHENTICATION_INFO, *PSOLE_AUTHENTICATION_INFO;
		[PInvokeData("objidl.h", MSDNShortId = "23beb1b1-e4b7-4282-9868-5caf40a69a61")]
		[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
		public struct SOLE_AUTHENTICATION_INFO
		{
			/// <summary>
			/// <para>The authentication service. This member can be a single value from the Authentication Service Constants.</para>
			/// </summary>
			public RPC_C_AUTHN_LEVEL dwAuthnSvc;

			/// <summary>
			/// <para>The authorization service. This member can be a single value from the Authorization Constants.</para>
			/// </summary>
			public RPC_C_AUTHZ dwAuthzSvc;

			/// <summary>
			/// <para>A pointer to the authentication information, whose type is specific to the authentication service identified by <c>dwAuthnSvc</c>.</para>
			/// <para>
			/// For Schannel (RPC_C_AUTHN_GSS_SCHANNEL), this member either points to a CERT_CONTEXT structure that contains the client's
			/// X.509 certificate or is <c>NULL</c> if the client has no certificate or wishes to remain anonymous to the server.
			/// </para>
			/// <para>
			/// For NTLMSSP (RPC_C_AUTHN_WINNT) and Kerberos (RPC_C_AUTHN_GSS_KERBEROS), this member points to a SEC_WINNT_AUTH_IDENTITY or
			/// SEC_WINNT_AUTH_IDENTITY_EX structure that contains the user name and password.
			/// </para>
			/// <para>
			/// For Snego (RPC_C_AUTHN_GSS_NEGOTIATE), this member is either <c>NULL</c>, points to a SEC_WINNT_AUTH_IDENTITY structure, or
			/// points to a SEC_WINNT_AUTH_IDENTITY_EX structure. If it is <c>NULL</c>, Snego will pick a list of authentication services
			/// based on those available on the client computer. If it points to a <c>SEC_WINNT_AUTH_IDENTITY_EX</c> structure, the
			/// structure's <c>PackageList</c> member must point to a string containing a comma-separated list of authentication service
			/// names and the <c>PackageListLength</c> member must give the number of bytes in the <c>PackageList</c> string. If
			/// <c>PackageList</c> is <c>NULL</c>, all calls using Snego will fail.
			/// </para>
			/// <para>
			/// For authentication services not registered with DCOM, <c>pAuthInfo</c> must be set to <c>NULL</c> and DCOM will use the
			/// process identity to represent the client. For more information, see COM and Security Packages.
			/// </para>
			/// </summary>
			public IntPtr pAuthInfo;
		}

		/// <summary>
		/// Indicates the default authentication information to use with each authentication service. When DCOM negotiates the default
		/// authentication service for a proxy, it picks the default authentication information from this list.
		/// </summary>
		// https://docs.microsoft.com/en-us/windows/desktop/api/objidl/ns-objidl-tagsole_authentication_list typedef struct
		// tagSOLE_AUTHENTICATION_LIST { DWORD cAuthInfo; SOLE_AUTHENTICATION_INFO *aAuthInfo; } SOLE_AUTHENTICATION_LIST, *PSOLE_AUTHENTICATION_LIST;
		[PInvokeData("objidl.h", MSDNShortId = "21f7aef3-b6be-41cc-a6ed-16d3778e3cee")]
		[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
		public struct SOLE_AUTHENTICATION_LIST : IArrayStruct<SOLE_AUTHENTICATION_INFO>
		{
			/// <summary>
			/// <para>The count of pointers in the array pointed to by <c>aAuthInfo</c>.</para>
			/// </summary>
			public uint cAuthInfo;

			/// <summary>
			/// An array of SOLE_AUTHENTICATION_INFO structures. Each of these structures contains an identifier for an authentication
			/// service, an identifier for the authorization service, and a pointer to authentication information to use with the specified
			/// authentication service.
			/// </summary>
			public IntPtr aAuthInfo;
		}

		/// <summary>
		/// <para>Identifies an authentication service that a server is willing to use to communicate to a client.</para>
		/// </summary>
		// https://docs.microsoft.com/en-us/windows/desktop/api/objidl/ns-objidl-tagsole_authentication_service typedef struct
		// tagSOLE_AUTHENTICATION_SERVICE { DWORD dwAuthnSvc; DWORD dwAuthzSvc; OLECHAR *pPrincipalName; HRESULT hr; } SOLE_AUTHENTICATION_SERVICE;
		[PInvokeData("objidl.h", MSDNShortId = "77fd15d7-54d4-4812-93d3-13a671e7afff")]
		[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
		public struct SOLE_AUTHENTICATION_SERVICE
		{
			/// <summary>
			/// <para>The authentication service. This member can be a single value from the Authentication Service Constants.</para>
			/// </summary>
			public RPC_C_AUTHN_LEVEL dwAuthnSvc;

			/// <summary>
			/// <para>The authorization service. This member can be a single value from the Authorization Constants.</para>
			/// </summary>
			public RPC_C_AUTHZ dwAuthzSvc;

			/// <summary>
			/// The principal name to be used with the authentication service. If the principal name is <c>NULL</c>, the current user
			/// identifier is assumed. A <c>NULL</c> principal name is allowed for NTLMSSP, Kerberos, and Snego authentication services but
			/// may not work for other authentication services. For Schannel, this member must point to a CERT_CONTEXT structure that
			/// contains the server's certificate; if it <c>NULL</c> and if a certificate for the current user does not exist,
			/// RPC_E_NO_GOOD_SECURITY_PACKAGES is returned.
			/// </summary>
			[MarshalAs(UnmanagedType.LPWStr)]
			public string pPrincipalName;

			/// <summary>
			/// When used in CoInitializeSecurity, set on return to indicate the status of the call to register the authentication services.
			/// </summary>
			public HRESULT hr;
		}
	}
}